Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for the NXP SAA7164 PCIe bridge
0004  *
0005  *  Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
0006  */
0007 
0008 #include "saa7164.h"
0009 
0010 /* The message bus to/from the firmware is a ring buffer in PCI address
0011  * space. Establish the defaults.
0012  */
0013 int saa7164_bus_setup(struct saa7164_dev *dev)
0014 {
0015     struct tmComResBusInfo *b   = &dev->bus;
0016 
0017     mutex_init(&b->lock);
0018 
0019     b->Type         = TYPE_BUS_PCIe;
0020     b->m_wMaxReqSize    = SAA_DEVICE_MAXREQUESTSIZE;
0021 
0022     b->m_pdwSetRing     = (u8 __iomem *)(dev->bmmio +
0023         ((u32)dev->busdesc.CommandRing));
0024 
0025     b->m_dwSizeSetRing  = SAA_DEVICE_BUFFERBLOCKSIZE;
0026 
0027     b->m_pdwGetRing     = (u8 __iomem *)(dev->bmmio +
0028         ((u32)dev->busdesc.ResponseRing));
0029 
0030     b->m_dwSizeGetRing  = SAA_DEVICE_BUFFERBLOCKSIZE;
0031 
0032     b->m_dwSetWritePos  = ((u32)dev->intfdesc.BARLocation) +
0033         (2 * sizeof(u64));
0034     b->m_dwSetReadPos   = b->m_dwSetWritePos + (1 * sizeof(u32));
0035 
0036     b->m_dwGetWritePos  = b->m_dwSetWritePos + (2 * sizeof(u32));
0037     b->m_dwGetReadPos   = b->m_dwSetWritePos + (3 * sizeof(u32));
0038 
0039     return 0;
0040 }
0041 
0042 void saa7164_bus_dump(struct saa7164_dev *dev)
0043 {
0044     struct tmComResBusInfo *b = &dev->bus;
0045 
0046     dprintk(DBGLVL_BUS, "Dumping the bus structure:\n");
0047     dprintk(DBGLVL_BUS, " .type             = %d\n", b->Type);
0048     dprintk(DBGLVL_BUS, " .dev->bmmio       = 0x%p\n", dev->bmmio);
0049     dprintk(DBGLVL_BUS, " .m_wMaxReqSize    = 0x%x\n", b->m_wMaxReqSize);
0050     dprintk(DBGLVL_BUS, " .m_pdwSetRing     = 0x%p\n", b->m_pdwSetRing);
0051     dprintk(DBGLVL_BUS, " .m_dwSizeSetRing  = 0x%x\n", b->m_dwSizeSetRing);
0052     dprintk(DBGLVL_BUS, " .m_pdwGetRing     = 0x%p\n", b->m_pdwGetRing);
0053     dprintk(DBGLVL_BUS, " .m_dwSizeGetRing  = 0x%x\n", b->m_dwSizeGetRing);
0054 
0055     dprintk(DBGLVL_BUS, " .m_dwSetReadPos   = 0x%x (0x%08x)\n",
0056         b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
0057 
0058     dprintk(DBGLVL_BUS, " .m_dwSetWritePos  = 0x%x (0x%08x)\n",
0059         b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
0060 
0061     dprintk(DBGLVL_BUS, " .m_dwGetReadPos   = 0x%x (0x%08x)\n",
0062         b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
0063 
0064     dprintk(DBGLVL_BUS, " .m_dwGetWritePos  = 0x%x (0x%08x)\n",
0065         b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
0066 
0067 }
0068 
0069 /* Intensionally throw a BUG() if the state of the message bus looks corrupt */
0070 static void saa7164_bus_verify(struct saa7164_dev *dev)
0071 {
0072     struct tmComResBusInfo *b = &dev->bus;
0073     int bug = 0;
0074 
0075     if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing)
0076         bug++;
0077 
0078     if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing)
0079         bug++;
0080 
0081     if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing)
0082         bug++;
0083 
0084     if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing)
0085         bug++;
0086 
0087     if (bug) {
0088         saa_debug = 0xffff; /* Ensure we get the bus dump */
0089         saa7164_bus_dump(dev);
0090         saa_debug = 1024; /* Ensure we get the bus dump */
0091         BUG();
0092     }
0093 }
0094 
0095 static void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo *m,
0096                 void *buf)
0097 {
0098     dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
0099     dprintk(DBGLVL_BUS, " .id               = %d\n",   m->id);
0100     dprintk(DBGLVL_BUS, " .flags            = 0x%x\n", m->flags);
0101     dprintk(DBGLVL_BUS, " .size             = 0x%x\n", m->size);
0102     dprintk(DBGLVL_BUS, " .command          = 0x%x\n", m->command);
0103     dprintk(DBGLVL_BUS, " .controlselector  = 0x%x\n", m->controlselector);
0104     dprintk(DBGLVL_BUS, " .seqno            = %d\n",   m->seqno);
0105     if (buf)
0106         dprintk(DBGLVL_BUS, " .buffer (ignored)\n");
0107 }
0108 
0109 /*
0110  * Places a command or a response on the bus. The implementation does not
0111  * know if it is a command or a response it just places the data on the
0112  * bus depending on the bus information given in the struct tmComResBusInfo
0113  * structure. If the command or response does not fit into the bus ring
0114  * buffer it will be refused.
0115  *
0116  * Return Value:
0117  *  SAA_OK     The function executed successfully.
0118  *  < 0        One or more members are not initialized.
0119  */
0120 int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
0121     void *buf)
0122 {
0123     struct tmComResBusInfo *bus = &dev->bus;
0124     u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
0125     u32 new_swp, space_rem;
0126     int ret = SAA_ERR_BAD_PARAMETER;
0127     u16 size;
0128 
0129     if (!msg) {
0130         printk(KERN_ERR "%s() !msg\n", __func__);
0131         return SAA_ERR_BAD_PARAMETER;
0132     }
0133 
0134     dprintk(DBGLVL_BUS, "%s()\n", __func__);
0135 
0136     saa7164_bus_verify(dev);
0137 
0138     if (msg->size > dev->bus.m_wMaxReqSize) {
0139         printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
0140             __func__);
0141         return SAA_ERR_BAD_PARAMETER;
0142     }
0143 
0144     if ((msg->size > 0) && (buf == NULL)) {
0145         printk(KERN_ERR "%s() Missing message buffer\n", __func__);
0146         return SAA_ERR_BAD_PARAMETER;
0147     }
0148 
0149     /* Lock the bus from any other access */
0150     mutex_lock(&bus->lock);
0151 
0152     bytes_to_write = sizeof(*msg) + msg->size;
0153     free_write_space = 0;
0154     timeout = SAA_BUS_TIMEOUT;
0155     curr_srp = saa7164_readl(bus->m_dwSetReadPos);
0156     curr_swp = saa7164_readl(bus->m_dwSetWritePos);
0157 
0158     /* Deal with ring wrapping issues */
0159     if (curr_srp > curr_swp)
0160         /* Deal with the wrapped ring */
0161         free_write_space = curr_srp - curr_swp;
0162     else
0163         /* The ring has not wrapped yet */
0164         free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
0165 
0166     dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
0167         bytes_to_write);
0168 
0169     dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
0170         free_write_space);
0171 
0172     dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
0173     dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
0174 
0175     /* Process the msg and write the content onto the bus */
0176     while (bytes_to_write >= free_write_space) {
0177 
0178         if (timeout-- == 0) {
0179             printk(KERN_ERR "%s() bus timeout\n", __func__);
0180             ret = SAA_ERR_NO_RESOURCES;
0181             goto out;
0182         }
0183 
0184         /* TODO: Review this delay, efficient? */
0185         /* Wait, allowing the hardware fetch time */
0186         mdelay(1);
0187 
0188         /* Check the space usage again */
0189         curr_srp = saa7164_readl(bus->m_dwSetReadPos);
0190 
0191         /* Deal with ring wrapping issues */
0192         if (curr_srp > curr_swp)
0193             /* Deal with the wrapped ring */
0194             free_write_space = curr_srp - curr_swp;
0195         else
0196             /* Read didn't wrap around the buffer */
0197             free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
0198                 curr_swp;
0199 
0200     }
0201 
0202     /* Calculate the new write position */
0203     new_swp = curr_swp + bytes_to_write;
0204 
0205     dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
0206     dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
0207         bus->m_dwSizeSetRing);
0208 
0209     /*
0210      * Make a copy of msg->size before it is converted to le16 since it is
0211      * used in the code below.
0212      */
0213     size = msg->size;
0214     /* Convert to le16/le32 */
0215     msg->size = (__force u16)cpu_to_le16(msg->size);
0216     msg->command = (__force u32)cpu_to_le32(msg->command);
0217     msg->controlselector = (__force u16)cpu_to_le16(msg->controlselector);
0218 
0219     /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
0220 
0221     /* Check if we're going to wrap again */
0222     if (new_swp > bus->m_dwSizeSetRing) {
0223 
0224         /* Ring wraps */
0225         new_swp -= bus->m_dwSizeSetRing;
0226 
0227         space_rem = bus->m_dwSizeSetRing - curr_swp;
0228 
0229         dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__,
0230             space_rem);
0231 
0232         dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__,
0233             (u32)sizeof(*msg));
0234 
0235         if (space_rem < sizeof(*msg)) {
0236             dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
0237 
0238             /* Split the msg into pieces as the ring wraps */
0239             memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem);
0240             memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem,
0241                 sizeof(*msg) - space_rem);
0242 
0243             memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
0244                 buf, size);
0245 
0246         } else if (space_rem == sizeof(*msg)) {
0247             dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
0248 
0249             /* Additional data at the beginning of the ring */
0250             memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
0251             memcpy_toio(bus->m_pdwSetRing, buf, size);
0252 
0253         } else {
0254             /* Additional data wraps around the ring */
0255             memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
0256             if (size > 0) {
0257                 memcpy_toio(bus->m_pdwSetRing + curr_swp +
0258                     sizeof(*msg), buf, space_rem -
0259                     sizeof(*msg));
0260                 memcpy_toio(bus->m_pdwSetRing, (u8 *)buf +
0261                     space_rem - sizeof(*msg),
0262                     bytes_to_write - space_rem);
0263             }
0264 
0265         }
0266 
0267     } /* (new_swp > bus->m_dwSizeSetRing) */
0268     else {
0269         dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
0270 
0271         /* The ring buffer doesn't wrap, two simple copies */
0272         memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
0273         memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
0274             size);
0275     }
0276 
0277     dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
0278 
0279     /* Update the bus write position */
0280     saa7164_writel(bus->m_dwSetWritePos, new_swp);
0281 
0282     /* Convert back to cpu after writing the msg to the ringbuffer. */
0283     msg->size = le16_to_cpu((__force __le16)msg->size);
0284     msg->command = le32_to_cpu((__force __le32)msg->command);
0285     msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
0286     ret = SAA_OK;
0287 
0288 out:
0289     saa7164_bus_dump(dev);
0290     mutex_unlock(&bus->lock);
0291     saa7164_bus_verify(dev);
0292     return ret;
0293 }
0294 
0295 /*
0296  * Receive a command or a response from the bus. The implementation does not
0297  * know if it is a command or a response it simply dequeues the data,
0298  * depending on the bus information given in the struct tmComResBusInfo
0299  * structure.
0300  *
0301  * Return Value:
0302  *  0          The function executed successfully.
0303  *  < 0        One or more members are not initialized.
0304  */
0305 int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
0306     void *buf, int peekonly)
0307 {
0308     struct tmComResBusInfo *bus = &dev->bus;
0309     u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
0310         new_grp, buf_size, space_rem;
0311     struct tmComResInfo msg_tmp;
0312     int ret = SAA_ERR_BAD_PARAMETER;
0313 
0314     saa7164_bus_verify(dev);
0315 
0316     if (msg == NULL)
0317         return ret;
0318 
0319     if (msg->size > dev->bus.m_wMaxReqSize) {
0320         printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
0321             __func__);
0322         return ret;
0323     }
0324 
0325     if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) {
0326         printk(KERN_ERR
0327             "%s() Missing msg buf, size should be %d bytes\n",
0328             __func__, msg->size);
0329         return ret;
0330     }
0331 
0332     mutex_lock(&bus->lock);
0333 
0334     /* Peek the bus to see if a msg exists, if it's not what we're expecting
0335      * then return cleanly else read the message from the bus.
0336      */
0337     curr_gwp = saa7164_readl(bus->m_dwGetWritePos);
0338     curr_grp = saa7164_readl(bus->m_dwGetReadPos);
0339 
0340     if (curr_gwp == curr_grp) {
0341         ret = SAA_ERR_EMPTY;
0342         goto out;
0343     }
0344 
0345     bytes_to_read = sizeof(*msg);
0346 
0347     /* Calculate write distance to current read position */
0348     write_distance = 0;
0349     if (curr_gwp >= curr_grp)
0350         /* Write doesn't wrap around the ring */
0351         write_distance = curr_gwp - curr_grp;
0352     else
0353         /* Write wraps around the ring */
0354         write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
0355 
0356     if (bytes_to_read > write_distance) {
0357         printk(KERN_ERR "%s() No message/response found\n", __func__);
0358         ret = SAA_ERR_INVALID_COMMAND;
0359         goto out;
0360     }
0361 
0362     /* Calculate the new read position */
0363     new_grp = curr_grp + bytes_to_read;
0364     if (new_grp > bus->m_dwSizeGetRing) {
0365 
0366         /* Ring wraps */
0367         new_grp -= bus->m_dwSizeGetRing;
0368         space_rem = bus->m_dwSizeGetRing - curr_grp;
0369 
0370         memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
0371         memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
0372             bytes_to_read - space_rem);
0373 
0374     } else {
0375         /* No wrapping */
0376         memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
0377     }
0378     /* Convert from little endian to CPU */
0379     msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
0380     msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
0381     msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
0382     memcpy(msg, &msg_tmp, sizeof(*msg));
0383 
0384     /* No need to update the read positions, because this was a peek */
0385     /* If the caller specifically want to peek, return */
0386     if (peekonly) {
0387         goto peekout;
0388     }
0389 
0390     /* Check if the command/response matches what is expected */
0391     if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) ||
0392         (msg_tmp.controlselector != msg->controlselector) ||
0393         (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) {
0394 
0395         printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__);
0396         saa7164_bus_dumpmsg(dev, msg, buf);
0397         saa7164_bus_dumpmsg(dev, &msg_tmp, NULL);
0398         ret = SAA_ERR_INVALID_COMMAND;
0399         goto out;
0400     }
0401 
0402     /* Get the actual command and response from the bus */
0403     buf_size = msg->size;
0404 
0405     bytes_to_read = sizeof(*msg) + msg->size;
0406     /* Calculate write distance to current read position */
0407     write_distance = 0;
0408     if (curr_gwp >= curr_grp)
0409         /* Write doesn't wrap around the ring */
0410         write_distance = curr_gwp - curr_grp;
0411     else
0412         /* Write wraps around the ring */
0413         write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp;
0414 
0415     if (bytes_to_read > write_distance) {
0416         printk(KERN_ERR "%s() Invalid bus state, missing msg or mangled ring, faulty H/W / bad code?\n",
0417                __func__);
0418         ret = SAA_ERR_INVALID_COMMAND;
0419         goto out;
0420     }
0421 
0422     /* Calculate the new read position */
0423     new_grp = curr_grp + bytes_to_read;
0424     if (new_grp > bus->m_dwSizeGetRing) {
0425 
0426         /* Ring wraps */
0427         new_grp -= bus->m_dwSizeGetRing;
0428         space_rem = bus->m_dwSizeGetRing - curr_grp;
0429 
0430         if (space_rem < sizeof(*msg)) {
0431             if (buf)
0432                 memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
0433                     space_rem, buf_size);
0434 
0435         } else if (space_rem == sizeof(*msg)) {
0436             if (buf)
0437                 memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
0438         } else {
0439             /* Additional data wraps around the ring */
0440             if (buf) {
0441                 memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
0442                     sizeof(*msg), space_rem - sizeof(*msg));
0443                 memcpy_fromio(buf + space_rem - sizeof(*msg),
0444                     bus->m_pdwGetRing, bytes_to_read -
0445                     space_rem);
0446             }
0447 
0448         }
0449 
0450     } else {
0451         /* No wrapping */
0452         if (buf)
0453             memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
0454                 buf_size);
0455     }
0456 
0457     /* Update the read positions, adjusting the ring */
0458     saa7164_writel(bus->m_dwGetReadPos, new_grp);
0459 
0460 peekout:
0461     ret = SAA_OK;
0462 out:
0463     mutex_unlock(&bus->lock);
0464     saa7164_bus_verify(dev);
0465     return ret;
0466 }
0467