[9610] wlbt: SMAPPER. Check DMA addr alignment
authorAlbert Cano <a.canocamps@samsung.com>
Fri, 1 Jun 2018 08:29:29 +0000 (09:29 +0100)
committerIvan Priest <i.priest@samsung.com>
Wed, 11 Jul 2018 17:43:16 +0000 (18:43 +0100)
Since SMAPPER bank entry base address forces alignment (i.e. 2048
octets), hip4_smapper alloc should validate the dma buffer (phys
address) before setting the entry.

Usually skb/dma allocation will 'guarantee' 4k alignment unless
SLUB/SLAB debug is enabled.

Extended the smapper api to get the aligment from platform device
virtual implementation

Change-Id: Ic03f952d029efad7c60281d33d6915470072a3b5
SCSC-Bug-Id: SSB-40382
Signed-off-by: Albert Cano <a.canocamps@samsung.com>
drivers/misc/samsung/scsc/mifsmapper.c
drivers/misc/samsung/scsc/mifsmapper.h
drivers/misc/samsung/scsc/platform_mif.c
drivers/misc/samsung/scsc/scsc_mif_abs.h
drivers/misc/samsung/scsc/scsc_service.c
drivers/net/wireless/scsc/hip4_smapper.c
drivers/net/wireless/scsc/hip4_smapper.h
include/scsc/scsc_mx.h

index 7d932719a1c4d4678d1c7eedbe8c3265b625d82a..924459c3c68852ddf1645d5525fe7cc3c1a116dd 100644 (file)
@@ -49,7 +49,7 @@ int mifsmapper_init(struct mifsmapper *smapper, struct scsc_mif_abs *mif)
 
        spin_lock_init(&smapper->lock);
        /* Get physical mapping of the banks */
-       if (mif->mif_smapper_get_mapping(mif, phy_map)) {
+       if (mif->mif_smapper_get_mapping(mif, phy_map, &smapper->align)) {
                SCSC_TAG_ERR(MIF, "SMAPPER is not present\n");
                return -EINVAL;
        }
@@ -100,6 +100,11 @@ int mifsmapper_init(struct mifsmapper *smapper, struct scsc_mif_abs *mif)
        return 0;
 }
 
+u16 mifsmapper_get_alignment(struct mifsmapper *smapper)
+{
+       return smapper->align;
+}
+
 int mifsmapper_alloc_bank(struct mifsmapper *smapper, bool large_bank, u32 entry_size, u16 *entries)
 {
        struct mifsmapper_bank *bank;
index ed75469c2093cf9460fb0fd99605235cead6f04f..715f1f5503a8a0b5e39885c5820bab4d1f145ecf 100644 (file)
@@ -13,6 +13,7 @@ struct scsc_mif_abs;
 struct mutex;
 
 int mifsmapper_init(struct mifsmapper *smapper, struct scsc_mif_abs *mif);
+u16 mifsmapper_get_alignment(struct mifsmapper *smapper);
 int mifsmapper_alloc_bank(struct mifsmapper *smapper, bool large_bank, u32 entry_size, u16 *entries);
 int mifsmapper_free_bank(struct mifsmapper *smapper, u8 bank);
 int mifsmapper_get_entries(struct mifsmapper *smapper, u8 bank, u8 num_entries, u8 *entr);
@@ -48,5 +49,6 @@ struct mifsmapper {
        unsigned long *bank_bm_small;
        u32 num_large_banks;
        u32 num_small_banks;
+       u16 align;
 };
 #endif
index 292e9fe34aa36d4a5213fc33e53c5b431a5c0e4f..85daccfbfad406aba10021f90ac39e53d432a686 100755 (executable)
@@ -228,8 +228,11 @@ inline u32 platform_mif_reg_read_smapper(struct platform_mif *platform, u16 offs
        return readl(platform->smapper_base + offset);
 }
 
+#define PLATFORM_MIF_SHIFT_SMAPPER_ADDR                11 /* From 36 bits addres to 25 bits */
+#define PLATFORM_MIF_SHIFT_SMAPPER_END         4  /* End address aligment */
+
 /* Platform is responsible to give the phys mapping of the SMAPPER maps */
-static int platform_mif_smapper_get_mapping(struct scsc_mif_abs *interface, u8 *phy_map)
+static int platform_mif_smapper_get_mapping(struct scsc_mif_abs *interface, u8 *phy_map, u16 *align)
 {
        struct platform_mif *platform = platform_mif_from_mif_abs(interface);
        u8 i;
@@ -246,6 +249,9 @@ static int platform_mif_smapper_get_mapping(struct scsc_mif_abs *interface, u8 *
                        phy_map[i] = SCSC_MIF_ABS_SMALL_BANK;
        }
 
+       if (align)
+               *align = 1 << PLATFORM_MIF_SHIFT_SMAPPER_ADDR;
+
        return 0;
 }
 
@@ -281,9 +287,6 @@ static u8 platform_mif_smapper_granularity_to_bits(u32 granularity)
        return 7;
 }
 
-#define PLATFORM_MIF_SHIFT_SMAPPER_ADDR                11 /* From 36 bits addres to 25 bits */
-#define PLATFORM_MIF_SHIFT_SMAPPER_END         4  /* From 36 bits addres to 25 bits */
-
 static u32 platform_mif_smapper_get_bank_base_address(struct scsc_mif_abs *interface, u8 bank)
 {
        struct platform_mif *platform = platform_mif_from_mif_abs(interface);
index 27f767ccbfdfc372144e8478cb3c9e30d140ecaa..8ce8caa15b5128e818fb6629fa7066ea2f42eb5e 100644 (file)
@@ -187,7 +187,7 @@ struct scsc_mif_abs {
 
 #ifdef CONFIG_SCSC_SMAPPER
 /* SMAPPER */
-       int  (*mif_smapper_get_mapping)(struct scsc_mif_abs *interface, u8 *phy_map);
+       int  (*mif_smapper_get_mapping)(struct scsc_mif_abs *interface, u8 *phy_map, u16 *align);
        int  (*mif_smapper_get_bank_info)(struct scsc_mif_abs *interface, u8 bank, struct scsc_mif_smapper_info *bank_info);
        int  (*mif_smapper_write_sram)(struct scsc_mif_abs *interface, u8 bank, u8 num_entries, u8 first_entry, dma_addr_t *addr);
        void (*mif_smapper_configure)(struct scsc_mif_abs *interface, u32 granularity);
index 1bc076908119f443e60e284ea18830e8448dd08d..27fbcbc390e8693d4a980370c0bc4ac858fca9b0 100755 (executable)
@@ -887,6 +887,13 @@ int scsc_service_force_panic(struct scsc_service *service)
 EXPORT_SYMBOL(scsc_service_force_panic);
 
 #ifdef CONFIG_SCSC_SMAPPER
+u16 scsc_service_get_alignment(struct scsc_service *service)
+{
+       struct scsc_mx *mx = service->mx;
+
+       return mifsmapper_get_alignment(scsc_mx_get_smapper(mx));
+}
+
 int scsc_service_mifsmapper_alloc_bank(struct scsc_service *service, bool large_bank, u32 entry_size, u16 *entries)
 {
        struct scsc_mx *mx = service->mx;
index c73b056c929b51af24d9ed48f72d8162659080eb..f6d9c8a4ebcfc03bfa42309e2f2c1bf17f8a1b12 100644 (file)
@@ -38,6 +38,7 @@ static int hip4_smapper_alloc_bank(struct slsi_dev *sdev, struct hip4_priv *priv
        for (i = 0; i < bank->entries; i++)
                bank->skbuff[i] = NULL;
 
+       bank->align = scsc_service_get_alignment(sdev->service);
        bank->in_use = true;
 
        return 0;
@@ -71,6 +72,15 @@ static int hip4_smapper_allocate_skb_buffers(struct slsi_dev *sdev, struct hip4_
                                slsi_kfree_skb(skb);
                                return err;
                        }
+
+                       /* Check alignment */
+                       if (!IS_ALIGNED(bank->skbuff_dma[i], bank->align)) {
+                               SLSI_DBG4_NODEV(SLSI_SMAPPER, "Phys address: 0x%x not %d aligned. Unmap memory and return error\n", bank->skbuff_dma[i], bank->align);
+                               dma_unmap_single(sdev->dev, bank->skbuff_dma[i], bank->entry_size, DMA_FROM_DEVICE);
+                               slsi_kfree_skb(skb);
+                               bank->skbuff_dma[i] = 0;
+                               return -ENOMEM;
+                       }
                        bank->skbuff[i] = skb;
                }
        }
index df2958e17e1a8768ce29249fcc6d226e9f3b6d35..37d54ca5d2931064080a5e450a7497c572d2eed4 100644 (file)
@@ -83,6 +83,7 @@ struct hip4_smapper_bank {
        struct sk_buff          **skbuff;
        dma_addr_t              *skbuff_dma;
        struct hip4_smapper_control_entry *entry;
+       u16 align;
 };
 
 int hip4_smapper_init(struct slsi_dev *sdev, struct slsi_hip4 *hip);
index 38cbddddd15023111dc7bd7d2e81d3f0a6449f05..0c17b3fcbee81147221302464c6af9809917a4e8 100755 (executable)
@@ -219,6 +219,8 @@ int scsc_service_mifsmapper_free_entries(struct scsc_service *service, u8 bank,
 /* Program SRAM entry */
 int scsc_service_mifsmapper_write_sram(struct scsc_service *service, u8 bank, u8 num_entries, u8 first_entry, dma_addr_t *addr);
 u32 scsc_service_mifsmapper_get_bank_base_address(struct scsc_service *service, u8 bank);
+/* Get SMAPPER aligment */
+u16 scsc_service_get_alignment(struct scsc_service *service);
 #endif
 
 int scsc_service_pm_qos_add_request(struct scsc_service *service, enum scsc_qos_config config);