LCOV - code coverage report
Current view: top level - drivers/ssb - sprom.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 86 0.0 %
Date: 2022-03-28 13:20:08 Functions: 0 7 0.0 %
Branches: 0 48 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Sonics Silicon Backplane
       3                 :            :  * Common SPROM support routines
       4                 :            :  *
       5                 :            :  * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
       6                 :            :  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
       7                 :            :  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
       8                 :            :  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
       9                 :            :  * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
      10                 :            :  *
      11                 :            :  * Licensed under the GNU/GPL. See COPYING for details.
      12                 :            :  */
      13                 :            : 
      14                 :            : #include "ssb_private.h"
      15                 :            : 
      16                 :            : #include <linux/ctype.h>
      17                 :            : #include <linux/slab.h>
      18                 :            : 
      19                 :            : 
      20                 :            : static int(*get_fallback_sprom)(struct ssb_bus *dev, struct ssb_sprom *out);
      21                 :            : 
      22                 :            : 
      23                 :          0 : static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
      24                 :            :                      size_t sprom_size_words)
      25                 :            : {
      26                 :          0 :         int i, pos = 0;
      27                 :            : 
      28         [ #  # ]:          0 :         for (i = 0; i < sprom_size_words; i++)
      29                 :          0 :                 pos += snprintf(buf + pos, buf_len - pos - 1,
      30                 :          0 :                                 "%04X", swab16(sprom[i]) & 0xFFFF);
      31                 :          0 :         pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
      32                 :            : 
      33                 :          0 :         return pos + 1;
      34                 :            : }
      35                 :            : 
      36                 :          0 : static int hex2sprom(u16 *sprom, const char *dump, size_t len,
      37                 :            :                      size_t sprom_size_words)
      38                 :            : {
      39                 :          0 :         char c, tmp[5] = { 0 };
      40                 :          0 :         int err, cnt = 0;
      41                 :          0 :         unsigned long parsed;
      42                 :            : 
      43                 :            :         /* Strip whitespace at the end. */
      44         [ #  # ]:          0 :         while (len) {
      45                 :          0 :                 c = dump[len - 1];
      46   [ #  #  #  # ]:          0 :                 if (!isspace(c) && c != '\0')
      47                 :            :                         break;
      48                 :            :                 len--;
      49                 :            :         }
      50                 :            :         /* Length must match exactly. */
      51         [ #  # ]:          0 :         if (len != sprom_size_words * 4)
      52                 :            :                 return -EINVAL;
      53                 :            : 
      54         [ #  # ]:          0 :         while (cnt < sprom_size_words) {
      55                 :          0 :                 memcpy(tmp, dump, 4);
      56                 :          0 :                 dump += 4;
      57                 :          0 :                 err = kstrtoul(tmp, 16, &parsed);
      58         [ #  # ]:          0 :                 if (err)
      59                 :          0 :                         return err;
      60                 :          0 :                 sprom[cnt++] = swab16((u16)parsed);
      61                 :            :         }
      62                 :            : 
      63                 :            :         return 0;
      64                 :            : }
      65                 :            : 
      66                 :            : /* Common sprom device-attribute show-handler */
      67                 :          0 : ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf,
      68                 :            :                             int (*sprom_read)(struct ssb_bus *bus, u16 *sprom))
      69                 :            : {
      70                 :          0 :         u16 *sprom;
      71                 :          0 :         int err = -ENOMEM;
      72                 :          0 :         ssize_t count = 0;
      73                 :          0 :         size_t sprom_size_words = bus->sprom_size;
      74                 :            : 
      75                 :          0 :         sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL);
      76         [ #  # ]:          0 :         if (!sprom)
      77                 :          0 :                 goto out;
      78                 :            : 
      79                 :            :         /* Use interruptible locking, as the SPROM write might
      80                 :            :          * be holding the lock for several seconds. So allow userspace
      81                 :            :          * to cancel operation. */
      82                 :          0 :         err = -ERESTARTSYS;
      83         [ #  # ]:          0 :         if (mutex_lock_interruptible(&bus->sprom_mutex))
      84                 :          0 :                 goto out_kfree;
      85                 :          0 :         err = sprom_read(bus, sprom);
      86                 :          0 :         mutex_unlock(&bus->sprom_mutex);
      87                 :            : 
      88         [ #  # ]:          0 :         if (!err)
      89                 :          0 :                 count = sprom2hex(sprom, buf, PAGE_SIZE, sprom_size_words);
      90                 :            : 
      91                 :          0 : out_kfree:
      92                 :          0 :         kfree(sprom);
      93                 :            : out:
      94         [ #  # ]:          0 :         return err ? err : count;
      95                 :            : }
      96                 :            : 
      97                 :            : /* Common sprom device-attribute store-handler */
      98                 :          0 : ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
      99                 :            :                              const char *buf, size_t count,
     100                 :            :                              int (*sprom_check_crc)(const u16 *sprom, size_t size),
     101                 :            :                              int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom))
     102                 :            : {
     103                 :          0 :         u16 *sprom;
     104                 :          0 :         int res = 0, err = -ENOMEM;
     105                 :          0 :         size_t sprom_size_words = bus->sprom_size;
     106                 :          0 :         struct ssb_freeze_context freeze;
     107                 :            : 
     108                 :          0 :         sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
     109         [ #  # ]:          0 :         if (!sprom)
     110                 :          0 :                 goto out;
     111                 :          0 :         err = hex2sprom(sprom, buf, count, sprom_size_words);
     112         [ #  # ]:          0 :         if (err) {
     113                 :          0 :                 err = -EINVAL;
     114                 :          0 :                 goto out_kfree;
     115                 :            :         }
     116                 :          0 :         err = sprom_check_crc(sprom, sprom_size_words);
     117         [ #  # ]:          0 :         if (err) {
     118                 :          0 :                 err = -EINVAL;
     119                 :          0 :                 goto out_kfree;
     120                 :            :         }
     121                 :            : 
     122                 :            :         /* Use interruptible locking, as the SPROM write might
     123                 :            :          * be holding the lock for several seconds. So allow userspace
     124                 :            :          * to cancel operation. */
     125                 :          0 :         err = -ERESTARTSYS;
     126         [ #  # ]:          0 :         if (mutex_lock_interruptible(&bus->sprom_mutex))
     127                 :          0 :                 goto out_kfree;
     128                 :          0 :         err = ssb_devices_freeze(bus, &freeze);
     129         [ #  # ]:          0 :         if (err) {
     130                 :          0 :                 pr_err("SPROM write: Could not freeze all devices\n");
     131                 :          0 :                 goto out_unlock;
     132                 :            :         }
     133                 :          0 :         res = sprom_write(bus, sprom);
     134                 :          0 :         err = ssb_devices_thaw(&freeze);
     135         [ #  # ]:          0 :         if (err)
     136                 :          0 :                 pr_err("SPROM write: Could not thaw all devices\n");
     137                 :          0 : out_unlock:
     138                 :          0 :         mutex_unlock(&bus->sprom_mutex);
     139                 :          0 : out_kfree:
     140                 :          0 :         kfree(sprom);
     141                 :            : out:
     142         [ #  # ]:          0 :         if (res)
     143                 :          0 :                 return res;
     144         [ #  # ]:          0 :         return err ? err : count;
     145                 :            : }
     146                 :            : 
     147                 :            : /**
     148                 :            :  * ssb_arch_register_fallback_sprom - Registers a method providing a
     149                 :            :  * fallback SPROM if no SPROM is found.
     150                 :            :  *
     151                 :            :  * @sprom_callback: The callback function.
     152                 :            :  *
     153                 :            :  * With this function the architecture implementation may register a
     154                 :            :  * callback handler which fills the SPROM data structure. The fallback is
     155                 :            :  * only used for PCI based SSB devices, where no valid SPROM can be found
     156                 :            :  * in the shadow registers.
     157                 :            :  *
     158                 :            :  * This function is useful for weird architectures that have a half-assed
     159                 :            :  * SSB device hardwired to their PCI bus.
     160                 :            :  *
     161                 :            :  * Note that it does only work with PCI attached SSB devices. PCMCIA
     162                 :            :  * devices currently don't use this fallback.
     163                 :            :  * Architectures must provide the SPROM for native SSB devices anyway, so
     164                 :            :  * the fallback also isn't used for native devices.
     165                 :            :  *
     166                 :            :  * This function is available for architecture code, only. So it is not
     167                 :            :  * exported.
     168                 :            :  */
     169                 :          0 : int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus,
     170                 :            :                                      struct ssb_sprom *out))
     171                 :            : {
     172         [ #  # ]:          0 :         if (get_fallback_sprom)
     173                 :            :                 return -EEXIST;
     174                 :          0 :         get_fallback_sprom = sprom_callback;
     175                 :            : 
     176                 :          0 :         return 0;
     177                 :            : }
     178                 :            : 
     179                 :          0 : int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out)
     180                 :            : {
     181         [ #  # ]:          0 :         if (!get_fallback_sprom)
     182                 :            :                 return -ENOENT;
     183                 :            : 
     184                 :          0 :         return get_fallback_sprom(bus, out);
     185                 :            : }
     186                 :            : 
     187                 :            : /* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
     188                 :          0 : bool ssb_is_sprom_available(struct ssb_bus *bus)
     189                 :            : {
     190                 :            :         /* status register only exists on chipcomon rev >= 11 and we need check
     191                 :            :            for >= 31 only */
     192                 :            :         /* this routine differs from specs as we do not access SPROM directly
     193                 :            :            on PCMCIA */
     194         [ #  # ]:          0 :         if (bus->bustype == SSB_BUSTYPE_PCI &&
     195         [ #  # ]:          0 :             bus->chipco.dev &&       /* can be unavailable! */
     196         [ #  # ]:          0 :             bus->chipco.dev->id.revision >= 31)
     197                 :          0 :                 return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
     198                 :            : 
     199                 :            :         return true;
     200                 :            : }

Generated by: LCOV version 1.14