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