linux/drivers/media/pci/saa7164/saa7164-bus.c
<<
>>
Prefs
   1/*
   2 *  Driver for the NXP SAA7164 PCIe bridge
   3 *
   4 *  Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *
  15 *  GNU General Public License for more details.
  16 */
  17
  18#include "saa7164.h"
  19
  20/* The message bus to/from the firmware is a ring buffer in PCI address
  21 * space. Establish the defaults.
  22 */
  23int saa7164_bus_setup(struct saa7164_dev *dev)
  24{
  25        struct tmComResBusInfo *b       = &dev->bus;
  26
  27        mutex_init(&b->lock);
  28
  29        b->Type                 = TYPE_BUS_PCIe;
  30        b->m_wMaxReqSize        = SAA_DEVICE_MAXREQUESTSIZE;
  31
  32        b->m_pdwSetRing         = (u8 __iomem *)(dev->bmmio +
  33                ((u32)dev->busdesc.CommandRing));
  34
  35        b->m_dwSizeSetRing      = SAA_DEVICE_BUFFERBLOCKSIZE;
  36
  37        b->m_pdwGetRing         = (u8 __iomem *)(dev->bmmio +
  38                ((u32)dev->busdesc.ResponseRing));
  39
  40        b->m_dwSizeGetRing      = SAA_DEVICE_BUFFERBLOCKSIZE;
  41
  42        b->m_dwSetWritePos      = ((u32)dev->intfdesc.BARLocation) +
  43                (2 * sizeof(u64));
  44        b->m_dwSetReadPos       = b->m_dwSetWritePos + (1 * sizeof(u32));
  45
  46        b->m_dwGetWritePos      = b->m_dwSetWritePos + (2 * sizeof(u32));
  47        b->m_dwGetReadPos       = b->m_dwSetWritePos + (3 * sizeof(u32));
  48
  49        return 0;
  50}
  51
  52void saa7164_bus_dump(struct saa7164_dev *dev)
  53{
  54        struct tmComResBusInfo *b = &dev->bus;
  55
  56        dprintk(DBGLVL_BUS, "Dumping the bus structure:\n");
  57        dprintk(DBGLVL_BUS, " .type             = %d\n", b->Type);
  58        dprintk(DBGLVL_BUS, " .dev->bmmio       = 0x%p\n", dev->bmmio);
  59        dprintk(DBGLVL_BUS, " .m_wMaxReqSize    = 0x%x\n", b->m_wMaxReqSize);
  60        dprintk(DBGLVL_BUS, " .m_pdwSetRing     = 0x%p\n", b->m_pdwSetRing);
  61        dprintk(DBGLVL_BUS, " .m_dwSizeSetRing  = 0x%x\n", b->m_dwSizeSetRing);
  62        dprintk(DBGLVL_BUS, " .m_pdwGetRing     = 0x%p\n", b->m_pdwGetRing);
  63        dprintk(DBGLVL_BUS, " .m_dwSizeGetRing  = 0x%x\n", b->m_dwSizeGetRing);
  64
  65        dprintk(DBGLVL_BUS, " .m_dwSetReadPos   = 0x%x (0x%08x)\n",
  66                b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
  67
  68        dprintk(DBGLVL_BUS, " .m_dwSetWritePos  = 0x%x (0x%08x)\n",
  69                b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
  70
  71        dprintk(DBGLVL_BUS, " .m_dwGetReadPos   = 0x%x (0x%08x)\n",
  72                b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
  73
  74        dprintk(DBGLVL_BUS, " .m_dwGetWritePos  = 0x%x (0x%08x)\n",
  75                b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
  76
  77}
  78
  79/* Intensionally throw a BUG() if the state of the message bus looks corrupt */
  80static void saa7164_bus_verify(struct saa7164_dev *dev)
  81{
  82        struct tmComResBusInfo *b = &dev->bus;
  83        int bug = 0;
  84
  85        if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing)
  86                bug++;
  87
  88        if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing)
  89                bug++;
  90
  91        if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing)
  92                bug++;
  93
  94        if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing)
  95                bug++;
  96
  97        if (bug) {
  98                saa_debug = 0xffff; /* Ensure we get the bus dump */
  99                saa7164_bus_dump(dev);
 100                saa_debug = 1024; /* Ensure we get the bus dump */
 101                BUG();
 102        }
 103}
 104
 105static void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo *m,
 106                                void *buf)
 107{
 108        dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
 109        dprintk(DBGLVL_BUS, " .id               = %d\n",   m->id);
 110        dprintk(DBGLVL_BUS, " .flags            = 0x%x\n", m->flags);
 111        dprintk(DBGLVL_BUS, " .size             = 0x%x\n", m->size);
 112        dprintk(DBGLVL_BUS, " .command          = 0x%x\n", m->command);
 113        dprintk(DBGLVL_BUS, " .controlselector  = 0x%x\n", m->controlselector);
 114        dprintk(DBGLVL_BUS, " .seqno            = %d\n",   m->seqno);
 115        if (buf)
 116                dprintk(DBGLVL_BUS, " .buffer (ignored)\n");
 117}
 118
 119/*
 120 * Places a command or a response on the bus. The implementation does not
 121 * know if it is a command or a response it just places the data on the
 122 * bus depending on the bus information given in the struct tmComResBusInfo
 123 * structure. If the command or response does not fit into the bus ring
 124 * buffer it will be refused.
 125 *
 126 * Return Value:
 127 *  SAA_OK     The function executed successfully.
 128 *  < 0        One or more members are not initialized.
 129 */
 130int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
 131        void *buf)
 132{
 133        struct tmComResBusInfo *bus = &dev->bus;
 134        u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
 135        u32 new_swp, space_rem;
 136        int ret = SAA_ERR_BAD_PARAMETER;
 137        u16 size;
 138
 139        if (!msg) {
 140                printk(KERN_ERR "%s() !msg\n", __func__);
 141                return SAA_ERR_BAD_PARAMETER;
 142        }
 143
 144        dprintk(DBGLVL_BUS, "%s()\n", __func__);
 145
 146        saa7164_bus_verify(dev);
 147
 148        if (msg->size > dev->bus.m_wMaxReqSize) {
 149                printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
 150                        __func__);
 151                return SAA_ERR_BAD_PARAMETER;
 152        }
 153
 154        if ((msg->size > 0) && (buf == NULL)) {
 155                printk(KERN_ERR "%s() Missing message buffer\n", __func__);
 156                return SAA_ERR_BAD_PARAMETER;
 157        }
 158
 159        /* Lock the bus from any other access */
 160        mutex_lock(&bus->lock);
 161
 162        bytes_to_write = sizeof(*msg) + msg->size;
 163        free_write_space = 0;
 164        timeout = SAA_BUS_TIMEOUT;
 165        curr_srp = saa7164_readl(bus->m_dwSetReadPos);
 166        curr_swp = saa7164_readl(bus->m_dwSetWritePos);
 167
 168        /* Deal with ring wrapping issues */
 169        if (curr_srp > curr_swp)
 170                /* Deal with the wrapped ring */
 171                free_write_space = curr_srp - curr_swp;
 172        else
 173                /* The ring has not wrapped yet */
 174                free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
 175
 176        dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
 177                bytes_to_write);
 178
 179        dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
 180                free_write_space);
 181
 182        dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
 183        dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
 184
 185        /* Process the msg and write the content onto the bus */
 186        while (bytes_to_write >= free_write_space) {
 187
 188                if (timeout-- == 0) {
 189                        printk(KERN_ERR "%s() bus timeout\n", __func__);
 190                        ret = SAA_ERR_NO_RESOURCES;
 191                        goto out;
 192                }
 193
 194                /* TODO: Review this delay, efficient? */
 195                /* Wait, allowing the hardware fetch time */
 196                mdelay(1);
 197
 198                /* Check the space usage again */
 199                curr_srp = saa7164_readl(bus->m_dwSetReadPos);
 200
 201                /* Deal with ring wrapping issues */
 202                if (curr_srp > curr_swp)
 203                        /* Deal with the wrapped ring */
 204                        free_write_space = curr_srp - curr_swp;
 205                else
 206                        /* Read didn't wrap around the buffer */
 207                        free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
 208                                curr_swp;
 209
 210        }
 211
 212        /* Calculate the new write position */
 213        new_swp = curr_swp + bytes_to_write;
 214
 215        dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
 216        dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
 217                bus->m_dwSizeSetRing);
 218
 219        /*
 220         * Make a copy of msg->size before it is converted to le16 since it is
 221         * used in the code below.
 222         */
 223        size = msg->size;
 224        /* Convert to le16/le32 */
 225        msg->size = (__force u16)cpu_to_le16(msg->size);
 226        msg->command = (__force u32)cpu_to_le32(msg->command);
 227        msg->controlselector = (__force u16)cpu_to_le16(msg->controlselector);
 228
 229        /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
 230
 231        /* Check if we're going to wrap again */
 232        if (new_swp > bus->m_dwSizeSetRing) {
 233
 234                /* Ring wraps */
 235                new_swp -= bus->m_dwSizeSetRing;
 236
 237                space_rem = bus->m_dwSizeSetRing - curr_swp;
 238
 239                dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
 240                        space_rem);
 241
 242                dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
 243                        (u32)sizeof(*msg));
 244
 245                if (space_rem < sizeof(*msg)) {
 246                        dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
 247
 248                        /* Split the msg into pieces as the ring wraps */
 249                        memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem);
 250                        memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem,
 251                                sizeof(*msg) - space_rem);
 252
 253                        memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
 254                                buf, size);
 255
 256                } else if (space_rem == sizeof(*msg)) {
 257                        dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
 258
 259                        /* Additional data at the beginning of the ring */
 260                        memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
 261                        memcpy_toio(bus->m_pdwSetRing, buf, size);
 262
 263                } else {
 264                        /* Additional data wraps around the ring */
 265                        memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
 266                        if (size > 0) {
 267                                memcpy_toio(bus->m_pdwSetRing + curr_swp +
 268                                        sizeof(*msg), buf, space_rem -
 269                                        sizeof(*msg));
 270                                memcpy_toio(bus->m_pdwSetRing, (u8 *)buf +
 271                                        space_rem - sizeof(*msg),
 272                                        bytes_to_write - space_rem);
 273                        }
 274
 275                }
 276
 277        } /* (new_swp > bus->m_dwSizeSetRing) */
 278        else {
 279                dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
 280
 281                /* The ring buffer doesn't wrap, two simple copies */
 282                memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
 283                memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
 284                        size);
 285        }
 286
 287        dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
 288
 289        /* Update the bus write position */
 290        saa7164_writel(bus->m_dwSetWritePos, new_swp);
 291
 292        /* Convert back to cpu after writing the msg to the ringbuffer. */
 293        msg->size = le16_to_cpu((__force __le16)msg->size);
 294        msg->command = le32_to_cpu((__force __le32)msg->command);
 295        msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
 296        ret = SAA_OK;
 297
 298out:
 299        saa7164_bus_dump(dev);
 300        mutex_unlock(&bus->lock);
 301        saa7164_bus_verify(dev);
 302        return ret;
 303}
 304
 305/*
 306 * Receive a command or a response from the bus. The implementation does not
 307 * know if it is a command or a response it simply dequeues the data,
 308 * depending on the bus information given in the struct tmComResBusInfo
 309 * structure.
 310 *
 311 * Return Value:
 312 *  0          The function executed successfully.
 313 *  < 0        One or more members are not initialized.
 314 */
 315int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
 316        void *buf, int peekonly)
 317{
 318        struct tmComResBusInfo *bus = &dev->bus;
 319        u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
 320                new_grp, buf_size, space_rem;
 321        struct tmComResInfo msg_tmp;
 322        int ret = SAA_ERR_BAD_PARAMETER;
 323
 324        saa7164_bus_verify(dev);
 325
 326        if (msg == NULL)
 327                return ret;
 328
 329        if (msg->size > dev->bus.m_wMaxReqSize) {
 330                printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
 331                        __func__);
 332                return ret;
 333        }
 334
 335        if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) {
 336                printk(KERN_ERR
 337                        "%s() Missing msg buf, size should be %d bytes\n",
 338                        __func__, msg->size);
 339                return ret;
 340        }
 341
 342        mutex_lock(&bus->lock);
 343
 344        /* Peek the bus to see if a msg exists, if it's not what we're expecting
 345         * then return cleanly else read the message from the bus.
 346         */
 347        curr_gwp = saa7164_readl(bus->m_dwGetWritePos);
 348        curr_grp = saa7164_readl(bus->m_dwGetReadPos);
 349
 350        if (curr_gwp == curr_grp) {
 351                ret = SAA_ERR_EMPTY;
 352                goto out;
 353        }
 354
 355        bytes_to_read = sizeof(*msg);
 356
 357        /* Calculate write distance to current read position */
 358        write_distance = 0;
 359        if (curr_gwp >= curr_grp)
 360                /* Write doesn't wrap around the ring */
 361                write_distance = curr_gwp - curr_grp;
 362        else
 363                /* Write wraps around the ring */
 364                write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
 365
 366        if (bytes_to_read > write_distance) {
 367                printk(KERN_ERR "%s() No message/response found\n", __func__);
 368                ret = SAA_ERR_INVALID_COMMAND;
 369                goto out;
 370        }
 371
 372        /* Calculate the new read position */
 373        new_grp = curr_grp + bytes_to_read;
 374        if (new_grp > bus->m_dwSizeGetRing) {
 375
 376                /* Ring wraps */
 377                new_grp -= bus->m_dwSizeGetRing;
 378                space_rem = bus->m_dwSizeGetRing - curr_grp;
 379
 380                memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
 381                memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
 382                        bytes_to_read - space_rem);
 383
 384        } else {
 385                /* No wrapping */
 386                memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
 387        }
 388        /* Convert from little endian to CPU */
 389        msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
 390        msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
 391        msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
 392        memcpy(msg, &msg_tmp, sizeof(*msg));
 393
 394        /* No need to update the read positions, because this was a peek */
 395        /* If the caller specifically want to peek, return */
 396        if (peekonly) {
 397                goto peekout;
 398        }
 399
 400        /* Check if the command/response matches what is expected */
 401        if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) ||
 402                (msg_tmp.controlselector != msg->controlselector) ||
 403                (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) {
 404
 405                printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__);
 406                saa7164_bus_dumpmsg(dev, msg, buf);
 407                saa7164_bus_dumpmsg(dev, &msg_tmp, NULL);
 408                ret = SAA_ERR_INVALID_COMMAND;
 409                goto out;
 410        }
 411
 412        /* Get the actual command and response from the bus */
 413        buf_size = msg->size;
 414
 415        bytes_to_read = sizeof(*msg) + msg->size;
 416        /* Calculate write distance to current read position */
 417        write_distance = 0;
 418        if (curr_gwp >= curr_grp)
 419                /* Write doesn't wrap around the ring */
 420                write_distance = curr_gwp - curr_grp;
 421        else
 422                /* Write wraps around the ring */
 423                write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
 424
 425        if (bytes_to_read > write_distance) {
 426                printk(KERN_ERR "%s() Invalid bus state, missing msg or mangled ring, faulty H/W / bad code?\n",
 427                       __func__);
 428                ret = SAA_ERR_INVALID_COMMAND;
 429                goto out;
 430        }
 431
 432        /* Calculate the new read position */
 433        new_grp = curr_grp + bytes_to_read;
 434        if (new_grp > bus->m_dwSizeGetRing) {
 435
 436                /* Ring wraps */
 437                new_grp -= bus->m_dwSizeGetRing;
 438                space_rem = bus->m_dwSizeGetRing - curr_grp;
 439
 440                if (space_rem < sizeof(*msg)) {
 441                        if (buf)
 442                                memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
 443                                        space_rem, buf_size);
 444
 445                } else if (space_rem == sizeof(*msg)) {
 446                        if (buf)
 447                                memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
 448                } else {
 449                        /* Additional data wraps around the ring */
 450                        if (buf) {
 451                                memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
 452                                        sizeof(*msg), space_rem - sizeof(*msg));
 453                                memcpy_fromio(buf + space_rem - sizeof(*msg),
 454                                        bus->m_pdwGetRing, bytes_to_read -
 455                                        space_rem);
 456                        }
 457
 458                }
 459
 460        } else {
 461                /* No wrapping */
 462                if (buf)
 463                        memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
 464                                buf_size);
 465        }
 466
 467        /* Update the read positions, adjusting the ring */
 468        saa7164_writel(bus->m_dwGetReadPos, new_grp);
 469
 470peekout:
 471        ret = SAA_OK;
 472out:
 473        mutex_unlock(&bus->lock);
 474        saa7164_bus_verify(dev);
 475        return ret;
 476}
 477
 478