Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*******************************************************************************
0003     AudioScience HPI driver
0004     Common Linux HPI ioctl and module probe/remove functions
0005 
0006     Copyright (C) 1997-2014  AudioScience Inc. <support@audioscience.com>
0007 
0008 
0009 *******************************************************************************/
0010 #define SOURCEFILE_NAME "hpioctl.c"
0011 
0012 #include "hpi_internal.h"
0013 #include "hpi_version.h"
0014 #include "hpimsginit.h"
0015 #include "hpidebug.h"
0016 #include "hpimsgx.h"
0017 #include "hpioctl.h"
0018 #include "hpicmn.h"
0019 
0020 #include <linux/fs.h>
0021 #include <linux/interrupt.h>
0022 #include <linux/slab.h>
0023 #include <linux/moduleparam.h>
0024 #include <linux/uaccess.h>
0025 #include <linux/pci.h>
0026 #include <linux/stringify.h>
0027 #include <linux/module.h>
0028 #include <linux/vmalloc.h>
0029 #include <linux/nospec.h>
0030 
0031 #ifdef MODULE_FIRMWARE
0032 MODULE_FIRMWARE("asihpi/dsp5000.bin");
0033 MODULE_FIRMWARE("asihpi/dsp6200.bin");
0034 MODULE_FIRMWARE("asihpi/dsp6205.bin");
0035 MODULE_FIRMWARE("asihpi/dsp6400.bin");
0036 MODULE_FIRMWARE("asihpi/dsp6600.bin");
0037 MODULE_FIRMWARE("asihpi/dsp8700.bin");
0038 MODULE_FIRMWARE("asihpi/dsp8900.bin");
0039 #endif
0040 
0041 static int prealloc_stream_buf;
0042 module_param(prealloc_stream_buf, int, 0444);
0043 MODULE_PARM_DESC(prealloc_stream_buf,
0044     "Preallocate size for per-adapter stream buffer");
0045 
0046 /* Allow the debug level to be changed after module load.
0047  E.g.   echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel
0048 */
0049 module_param(hpi_debug_level, int, 0644);
0050 MODULE_PARM_DESC(hpi_debug_level, "debug verbosity 0..5");
0051 
0052 /* List of adapters found */
0053 static struct hpi_adapter adapters[HPI_MAX_ADAPTERS];
0054 
0055 /* Wrapper function to HPI_Message to enable dumping of the
0056    message and response types.
0057 */
0058 static void hpi_send_recv_f(struct hpi_message *phm, struct hpi_response *phr,
0059     struct file *file)
0060 {
0061     if ((phm->adapter_index >= HPI_MAX_ADAPTERS)
0062         && (phm->object != HPI_OBJ_SUBSYSTEM))
0063         phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
0064     else
0065         hpi_send_recv_ex(phm, phr, file);
0066 }
0067 
0068 /* This is called from hpifunc.c functions, called by ALSA
0069  * (or other kernel process) In this case there is no file descriptor
0070  * available for the message cache code
0071  */
0072 void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr)
0073 {
0074     hpi_send_recv_f(phm, phr, HOWNER_KERNEL);
0075 }
0076 
0077 EXPORT_SYMBOL(hpi_send_recv);
0078 /* for radio-asihpi */
0079 
0080 int asihpi_hpi_release(struct file *file)
0081 {
0082     struct hpi_message hm;
0083     struct hpi_response hr;
0084 
0085 /* HPI_DEBUG_LOG(INFO,"hpi_release file %p, pid %d\n", file, current->pid); */
0086     /* close the subsystem just in case the application forgot to. */
0087     hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
0088         HPI_SUBSYS_CLOSE);
0089     hpi_send_recv_ex(&hm, &hr, file);
0090     return 0;
0091 }
0092 
0093 long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0094 {
0095     struct hpi_ioctl_linux __user *phpi_ioctl_data;
0096     void __user *puhm;
0097     void __user *puhr;
0098     union hpi_message_buffer_v1 *hm;
0099     union hpi_response_buffer_v1 *hr;
0100     u16 msg_size;
0101     u16 res_max_size;
0102     u32 uncopied_bytes;
0103     int err = 0;
0104 
0105     if (cmd != HPI_IOCTL_LINUX)
0106         return -EINVAL;
0107 
0108     hm = kmalloc(sizeof(*hm), GFP_KERNEL);
0109     hr = kzalloc(sizeof(*hr), GFP_KERNEL);
0110     if (!hm || !hr) {
0111         err = -ENOMEM;
0112         goto out;
0113     }
0114 
0115     phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg;
0116 
0117     /* Read the message and response pointers from user space.  */
0118     if (get_user(puhm, &phpi_ioctl_data->phm)
0119         || get_user(puhr, &phpi_ioctl_data->phr)) {
0120         err = -EFAULT;
0121         goto out;
0122     }
0123 
0124     /* Now read the message size and data from user space.  */
0125     if (get_user(msg_size, (u16 __user *)puhm)) {
0126         err = -EFAULT;
0127         goto out;
0128     }
0129     if (msg_size > sizeof(*hm))
0130         msg_size = sizeof(*hm);
0131 
0132     /* printk(KERN_INFO "message size %d\n", hm->h.wSize); */
0133 
0134     uncopied_bytes = copy_from_user(hm, puhm, msg_size);
0135     if (uncopied_bytes) {
0136         HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes);
0137         err = -EFAULT;
0138         goto out;
0139     }
0140 
0141     /* Override h.size in case it is changed between two userspace fetches */
0142     hm->h.size = msg_size;
0143 
0144     if (get_user(res_max_size, (u16 __user *)puhr)) {
0145         err = -EFAULT;
0146         goto out;
0147     }
0148     /* printk(KERN_INFO "user response size %d\n", res_max_size); */
0149     if (res_max_size < sizeof(struct hpi_response_header)) {
0150         HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size);
0151         err = -EFAULT;
0152         goto out;
0153     }
0154 
0155     res_max_size = min_t(size_t, res_max_size, sizeof(*hr));
0156 
0157     switch (hm->h.function) {
0158     case HPI_SUBSYS_CREATE_ADAPTER:
0159     case HPI_ADAPTER_DELETE:
0160         /* Application must not use these functions! */
0161         hr->h.size = sizeof(hr->h);
0162         hr->h.error = HPI_ERROR_INVALID_OPERATION;
0163         hr->h.function = hm->h.function;
0164         uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
0165         if (uncopied_bytes)
0166             err = -EFAULT;
0167         else
0168             err = 0;
0169         goto out;
0170     }
0171 
0172     hr->h.size = res_max_size;
0173     if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
0174         hpi_send_recv_f(&hm->m0, &hr->r0, file);
0175     } else {
0176         u16 __user *ptr = NULL;
0177         u32 size = 0;
0178         /* -1=no data 0=read from user mem, 1=write to user mem */
0179         int wrflag = -1;
0180         struct hpi_adapter *pa = NULL;
0181 
0182         if (hm->h.adapter_index < ARRAY_SIZE(adapters))
0183             pa = &adapters[array_index_nospec(hm->h.adapter_index,
0184                               ARRAY_SIZE(adapters))];
0185 
0186         if (!pa || !pa->adapter || !pa->adapter->type) {
0187             hpi_init_response(&hr->r0, hm->h.object,
0188                 hm->h.function, HPI_ERROR_BAD_ADAPTER_NUMBER);
0189 
0190             uncopied_bytes =
0191                 copy_to_user(puhr, hr, sizeof(hr->h));
0192             if (uncopied_bytes)
0193                 err = -EFAULT;
0194             else
0195                 err = 0;
0196             goto out;
0197         }
0198 
0199         if (mutex_lock_interruptible(&pa->mutex)) {
0200             err = -EINTR;
0201             goto out;
0202         }
0203 
0204         /* Dig out any pointers embedded in the message.  */
0205         switch (hm->h.function) {
0206         case HPI_OSTREAM_WRITE:
0207         case HPI_ISTREAM_READ:{
0208                 /* Yes, sparse, this is correct. */
0209                 ptr = (u16 __user *)hm->m0.u.d.u.data.pb_data;
0210                 size = hm->m0.u.d.u.data.data_size;
0211 
0212                 /* Allocate buffer according to application request.
0213                    ?Is it better to alloc/free for the duration
0214                    of the transaction?
0215                  */
0216                 if (pa->buffer_size < size) {
0217                     HPI_DEBUG_LOG(DEBUG,
0218                         "Realloc adapter %d stream "
0219                         "buffer from %zd to %d\n",
0220                         hm->h.adapter_index,
0221                         pa->buffer_size, size);
0222                     if (pa->p_buffer) {
0223                         pa->buffer_size = 0;
0224                         vfree(pa->p_buffer);
0225                     }
0226                     pa->p_buffer = vmalloc(size);
0227                     if (pa->p_buffer)
0228                         pa->buffer_size = size;
0229                     else {
0230                         HPI_DEBUG_LOG(ERROR,
0231                             "HPI could not allocate "
0232                             "stream buffer size %d\n",
0233                             size);
0234 
0235                         mutex_unlock(&pa->mutex);
0236                         err = -EINVAL;
0237                         goto out;
0238                     }
0239                 }
0240 
0241                 hm->m0.u.d.u.data.pb_data = pa->p_buffer;
0242                 if (hm->h.function == HPI_ISTREAM_READ)
0243                     /* from card, WRITE to user mem */
0244                     wrflag = 1;
0245                 else
0246                     wrflag = 0;
0247                 break;
0248             }
0249 
0250         default:
0251             size = 0;
0252             break;
0253         }
0254 
0255         if (size && (wrflag == 0)) {
0256             uncopied_bytes =
0257                 copy_from_user(pa->p_buffer, ptr, size);
0258             if (uncopied_bytes)
0259                 HPI_DEBUG_LOG(WARNING,
0260                     "Missed %d of %d "
0261                     "bytes from user\n", uncopied_bytes,
0262                     size);
0263         }
0264 
0265         hpi_send_recv_f(&hm->m0, &hr->r0, file);
0266 
0267         if (size && (wrflag == 1)) {
0268             uncopied_bytes =
0269                 copy_to_user(ptr, pa->p_buffer, size);
0270             if (uncopied_bytes)
0271                 HPI_DEBUG_LOG(WARNING,
0272                     "Missed %d of %d " "bytes to user\n",
0273                     uncopied_bytes, size);
0274         }
0275 
0276         mutex_unlock(&pa->mutex);
0277     }
0278 
0279     /* on return response size must be set */
0280     /*printk(KERN_INFO "response size %d\n", hr->h.wSize); */
0281 
0282     if (!hr->h.size) {
0283         HPI_DEBUG_LOG(ERROR, "response zero size\n");
0284         err = -EFAULT;
0285         goto out;
0286     }
0287 
0288     if (hr->h.size > res_max_size) {
0289         HPI_DEBUG_LOG(ERROR, "response too big %d %d\n", hr->h.size,
0290             res_max_size);
0291         hr->h.error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
0292         hr->h.specific_error = hr->h.size;
0293         hr->h.size = sizeof(hr->h);
0294     }
0295 
0296     uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
0297     if (uncopied_bytes) {
0298         HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes);
0299         err = -EFAULT;
0300         goto out;
0301     }
0302 
0303 out:
0304     kfree(hm);
0305     kfree(hr);
0306     return err;
0307 }
0308 
0309 static int asihpi_irq_count;
0310 
0311 static irqreturn_t asihpi_isr(int irq, void *dev_id)
0312 {
0313     struct hpi_adapter *a = dev_id;
0314     int handled;
0315 
0316     if (!a->adapter->irq_query_and_clear) {
0317         pr_err("asihpi_isr ASI%04X:%d no handler\n", a->adapter->type,
0318             a->adapter->index);
0319         return IRQ_NONE;
0320     }
0321 
0322     handled = a->adapter->irq_query_and_clear(a->adapter, 0);
0323 
0324     if (!handled)
0325         return IRQ_NONE;
0326 
0327     asihpi_irq_count++;
0328     /* printk(KERN_INFO "asihpi_isr %d ASI%04X:%d irq handled\n",
0329        asihpi_irq_count, a->adapter->type, a->adapter->index); */
0330 
0331     if (a->interrupt_callback)
0332         return IRQ_WAKE_THREAD;
0333 
0334     return IRQ_HANDLED;
0335 }
0336 
0337 static irqreturn_t asihpi_isr_thread(int irq, void *dev_id)
0338 {
0339     struct hpi_adapter *a = dev_id;
0340 
0341     if (a->interrupt_callback)
0342         a->interrupt_callback(a);
0343     return IRQ_HANDLED;
0344 }
0345 
0346 int asihpi_adapter_probe(struct pci_dev *pci_dev,
0347              const struct pci_device_id *pci_id)
0348 {
0349     int idx, nm, low_latency_mode = 0, irq_supported = 0;
0350     int adapter_index;
0351     unsigned int memlen;
0352     struct hpi_message hm;
0353     struct hpi_response hr;
0354     struct hpi_adapter adapter;
0355     struct hpi_pci pci = { 0 };
0356 
0357     memset(&adapter, 0, sizeof(adapter));
0358 
0359     dev_printk(KERN_DEBUG, &pci_dev->dev,
0360         "probe %04x:%04x,%04x:%04x,%04x\n", pci_dev->vendor,
0361         pci_dev->device, pci_dev->subsystem_vendor,
0362         pci_dev->subsystem_device, pci_dev->devfn);
0363 
0364     if (pci_enable_device(pci_dev) < 0) {
0365         dev_err(&pci_dev->dev,
0366             "pci_enable_device failed, disabling device\n");
0367         return -EIO;
0368     }
0369 
0370     pci_set_master(pci_dev);    /* also sets latency timer if < 16 */
0371 
0372     hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
0373         HPI_SUBSYS_CREATE_ADAPTER);
0374     hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER,
0375         HPI_ERROR_PROCESSING_MESSAGE);
0376 
0377     hm.adapter_index = HPI_ADAPTER_INDEX_INVALID;
0378 
0379     nm = HPI_MAX_ADAPTER_MEM_SPACES;
0380 
0381     for (idx = 0; idx < nm; idx++) {
0382         HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx,
0383             &pci_dev->resource[idx]);
0384 
0385         if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
0386             memlen = pci_resource_len(pci_dev, idx);
0387             pci.ap_mem_base[idx] =
0388                 ioremap(pci_resource_start(pci_dev, idx),
0389                 memlen);
0390             if (!pci.ap_mem_base[idx]) {
0391                 HPI_DEBUG_LOG(ERROR,
0392                     "ioremap failed, aborting\n");
0393                 /* unmap previously mapped pci mem space */
0394                 goto err;
0395             }
0396         }
0397     }
0398 
0399     pci.pci_dev = pci_dev;
0400     hm.u.s.resource.bus_type = HPI_BUS_PCI;
0401     hm.u.s.resource.r.pci = &pci;
0402 
0403     /* call CreateAdapterObject on the relevant hpi module */
0404     hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0405     if (hr.error)
0406         goto err;
0407 
0408     adapter_index = hr.u.s.adapter_index;
0409     adapter.adapter = hpi_find_adapter(adapter_index);
0410 
0411     if (prealloc_stream_buf) {
0412         adapter.p_buffer = vmalloc(prealloc_stream_buf);
0413         if (!adapter.p_buffer) {
0414             HPI_DEBUG_LOG(ERROR,
0415                 "HPI could not allocate "
0416                 "kernel buffer size %d\n",
0417                 prealloc_stream_buf);
0418             goto err;
0419         }
0420     }
0421 
0422     hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
0423         HPI_ADAPTER_OPEN);
0424     hm.adapter_index = adapter.adapter->index;
0425     hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0426 
0427     if (hr.error) {
0428         HPI_DEBUG_LOG(ERROR, "HPI_ADAPTER_OPEN failed, aborting\n");
0429         goto err;
0430     }
0431 
0432     /* Check if current mode == Low Latency mode */
0433     hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
0434         HPI_ADAPTER_GET_MODE);
0435     hm.adapter_index = adapter.adapter->index;
0436     hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0437 
0438     if (!hr.error
0439         && hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY)
0440         low_latency_mode = 1;
0441     else
0442         dev_info(&pci_dev->dev,
0443             "Adapter at index %d is not in low latency mode\n",
0444             adapter.adapter->index);
0445 
0446     /* Check if IRQs are supported */
0447     hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
0448         HPI_ADAPTER_GET_PROPERTY);
0449     hm.adapter_index = adapter.adapter->index;
0450     hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ;
0451     hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0452     if (hr.error || !hr.u.ax.property_get.parameter1) {
0453         dev_info(&pci_dev->dev,
0454             "IRQs not supported by adapter at index %d\n",
0455             adapter.adapter->index);
0456     } else {
0457         irq_supported = 1;
0458     }
0459 
0460     /* WARNING can't init mutex in 'adapter'
0461      * and then copy it to adapters[] ?!?!
0462      */
0463     adapters[adapter_index] = adapter;
0464     mutex_init(&adapters[adapter_index].mutex);
0465     pci_set_drvdata(pci_dev, &adapters[adapter_index]);
0466 
0467     if (low_latency_mode && irq_supported) {
0468         if (!adapter.adapter->irq_query_and_clear) {
0469             dev_err(&pci_dev->dev,
0470                 "no IRQ handler for adapter %d, aborting\n",
0471                 adapter.adapter->index);
0472             goto err;
0473         }
0474 
0475         /* Disable IRQ generation on DSP side by setting the rate to 0 */
0476         hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
0477             HPI_ADAPTER_SET_PROPERTY);
0478         hm.adapter_index = adapter.adapter->index;
0479         hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE;
0480         hm.u.ax.property_set.parameter1 = 0;
0481         hm.u.ax.property_set.parameter2 = 0;
0482         hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0483         if (hr.error) {
0484             HPI_DEBUG_LOG(ERROR,
0485                 "HPI_ADAPTER_GET_MODE failed, aborting\n");
0486             goto err;
0487         }
0488 
0489         /* Note: request_irq calls asihpi_isr here */
0490         if (request_threaded_irq(pci_dev->irq, asihpi_isr,
0491                      asihpi_isr_thread, IRQF_SHARED,
0492                      "asihpi", &adapters[adapter_index])) {
0493             dev_err(&pci_dev->dev, "request_irq(%d) failed\n",
0494                 pci_dev->irq);
0495             goto err;
0496         }
0497 
0498         adapters[adapter_index].interrupt_mode = 1;
0499 
0500         dev_info(&pci_dev->dev, "using irq %d\n", pci_dev->irq);
0501         adapters[adapter_index].irq = pci_dev->irq;
0502     } else {
0503         dev_info(&pci_dev->dev, "using polled mode\n");
0504     }
0505 
0506     dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n",
0507          adapter.adapter->type, adapter_index);
0508 
0509     return 0;
0510 
0511 err:
0512     while (--idx >= 0) {
0513         if (pci.ap_mem_base[idx]) {
0514             iounmap(pci.ap_mem_base[idx]);
0515             pci.ap_mem_base[idx] = NULL;
0516         }
0517     }
0518 
0519     if (adapter.p_buffer) {
0520         adapter.buffer_size = 0;
0521         vfree(adapter.p_buffer);
0522     }
0523 
0524     HPI_DEBUG_LOG(ERROR, "adapter_probe failed\n");
0525     return -ENODEV;
0526 }
0527 
0528 void asihpi_adapter_remove(struct pci_dev *pci_dev)
0529 {
0530     int idx;
0531     struct hpi_message hm;
0532     struct hpi_response hr;
0533     struct hpi_adapter *pa;
0534     struct hpi_pci pci;
0535 
0536     pa = pci_get_drvdata(pci_dev);
0537     pci = pa->adapter->pci;
0538 
0539     /* Disable IRQ generation on DSP side */
0540     hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
0541         HPI_ADAPTER_SET_PROPERTY);
0542     hm.adapter_index = pa->adapter->index;
0543     hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE;
0544     hm.u.ax.property_set.parameter1 = 0;
0545     hm.u.ax.property_set.parameter2 = 0;
0546     hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0547 
0548     hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
0549         HPI_ADAPTER_DELETE);
0550     hm.adapter_index = pa->adapter->index;
0551     hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0552 
0553     /* unmap PCI memory space, mapped during device init. */
0554     for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx)
0555         iounmap(pci.ap_mem_base[idx]);
0556 
0557     if (pa->irq)
0558         free_irq(pa->irq, pa);
0559 
0560     vfree(pa->p_buffer);
0561 
0562     if (1)
0563         dev_info(&pci_dev->dev,
0564              "remove %04x:%04x,%04x:%04x,%04x, HPI index %d\n",
0565              pci_dev->vendor, pci_dev->device,
0566              pci_dev->subsystem_vendor, pci_dev->subsystem_device,
0567              pci_dev->devfn, pa->adapter->index);
0568 
0569     memset(pa, 0, sizeof(*pa));
0570 }
0571 
0572 void __init asihpi_init(void)
0573 {
0574     struct hpi_message hm;
0575     struct hpi_response hr;
0576 
0577     memset(adapters, 0, sizeof(adapters));
0578 
0579     printk(KERN_INFO "ASIHPI driver " HPI_VER_STRING "\n");
0580 
0581     hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
0582         HPI_SUBSYS_DRIVER_LOAD);
0583     hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0584 }
0585 
0586 void asihpi_exit(void)
0587 {
0588     struct hpi_message hm;
0589     struct hpi_response hr;
0590 
0591     hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
0592         HPI_SUBSYS_DRIVER_UNLOAD);
0593     hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
0594 }