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