1443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* 2443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Driver for the NXP SAA7164 PCIe bridge 3443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 49b8b0199b86eaa595e3ccacb413e955a193f1962Steven Toth * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> 5443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 6443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * This program is free software; you can redistribute it and/or modify 7443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * it under the terms of the GNU General Public License as published by 8443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * the Free Software Foundation; either version 2 of the License, or 9443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * (at your option) any later version. 10443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 11443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * This program is distributed in the hope that it will be useful, 12443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * but WITHOUT ANY WARRANTY; without even the implied warranty of 13443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 15443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * GNU General Public License for more details. 16443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 17443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * You should have received a copy of the GNU General Public License 18443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * along with this program; if not, write to the Free Software 19443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 21443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 22443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth#include "saa7164.h" 23443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 24443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* The message bus to/from the firmware is a ring buffer in PCI address 25443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * space. Establish the defaults. 26443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 27443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothint saa7164_bus_setup(struct saa7164_dev *dev) 28443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 294d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResBusInfo *b = &dev->bus; 30443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 31443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_init(&b->lock); 32443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 33443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->Type = TYPE_BUS_PCIe; 34443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE; 35443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 36443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwSetRing = (u8 *)(dev->bmmio + 37443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ((u32)dev->busdesc.CommandRing)); 38443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 39443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE; 40443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 41443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_pdwGetRing = (u8 *)(dev->bmmio + 42443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ((u32)dev->busdesc.ResponseRing)); 43443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 44443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE; 45443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 46bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth b->m_dwSetWritePos = ((u32)dev->intfdesc.BARLocation) + 47bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth (2 * sizeof(u64)); 48606658292a0f8dc01f3165e741b711572af2d83fSteven Toth b->m_dwSetReadPos = b->m_dwSetWritePos + (1 * sizeof(u32)); 49443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 50606658292a0f8dc01f3165e741b711572af2d83fSteven Toth b->m_dwGetWritePos = b->m_dwSetWritePos + (2 * sizeof(u32)); 51606658292a0f8dc01f3165e741b711572af2d83fSteven Toth b->m_dwGetReadPos = b->m_dwSetWritePos + (3 * sizeof(u32)); 52443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 53443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return 0; 54443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 55443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 56443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothvoid saa7164_bus_dump(struct saa7164_dev *dev) 57443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 584d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResBusInfo *b = &dev->bus; 59443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 60443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "Dumping the bus structure:\n"); 61443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .type = %d\n", b->Type); 62443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .dev->bmmio = 0x%p\n", dev->bmmio); 63443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_wMaxReqSize = 0x%x\n", b->m_wMaxReqSize); 64443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_pdwSetRing = 0x%p\n", b->m_pdwSetRing); 65443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_dwSizeSetRing = 0x%x\n", b->m_dwSizeSetRing); 66443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing); 67443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing); 68443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 69606658292a0f8dc01f3165e741b711572af2d83fSteven Toth dprintk(DBGLVL_BUS, " .m_dwSetReadPos = 0x%x (0x%08x)\n", 70606658292a0f8dc01f3165e741b711572af2d83fSteven Toth b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos)); 71606658292a0f8dc01f3165e741b711572af2d83fSteven Toth 72606658292a0f8dc01f3165e741b711572af2d83fSteven Toth dprintk(DBGLVL_BUS, " .m_dwSetWritePos = 0x%x (0x%08x)\n", 73606658292a0f8dc01f3165e741b711572af2d83fSteven Toth b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos)); 74443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 75606658292a0f8dc01f3165e741b711572af2d83fSteven Toth dprintk(DBGLVL_BUS, " .m_dwGetReadPos = 0x%x (0x%08x)\n", 76606658292a0f8dc01f3165e741b711572af2d83fSteven Toth b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos)); 77443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 78606658292a0f8dc01f3165e741b711572af2d83fSteven Toth dprintk(DBGLVL_BUS, " .m_dwGetWritePos = 0x%x (0x%08x)\n", 79606658292a0f8dc01f3165e741b711572af2d83fSteven Toth b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos)); 80443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 81606658292a0f8dc01f3165e741b711572af2d83fSteven Toth} 82606658292a0f8dc01f3165e741b711572af2d83fSteven Toth 83606658292a0f8dc01f3165e741b711572af2d83fSteven Toth/* Intensionally throw a BUG() if the state of the message bus looks corrupt */ 84606658292a0f8dc01f3165e741b711572af2d83fSteven Tothvoid saa7164_bus_verify(struct saa7164_dev *dev) 85606658292a0f8dc01f3165e741b711572af2d83fSteven Toth{ 864d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResBusInfo *b = &dev->bus; 8799b73d38fa014bcf0f08557cf716907eceffaa1cSteven Toth int bug = 0; 88606658292a0f8dc01f3165e741b711572af2d83fSteven Toth 89606658292a0f8dc01f3165e741b711572af2d83fSteven Toth if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing) 90606658292a0f8dc01f3165e741b711572af2d83fSteven Toth bug++; 91606658292a0f8dc01f3165e741b711572af2d83fSteven Toth 92606658292a0f8dc01f3165e741b711572af2d83fSteven Toth if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing) 93606658292a0f8dc01f3165e741b711572af2d83fSteven Toth bug++; 94606658292a0f8dc01f3165e741b711572af2d83fSteven Toth 95606658292a0f8dc01f3165e741b711572af2d83fSteven Toth if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing) 96606658292a0f8dc01f3165e741b711572af2d83fSteven Toth bug++; 97606658292a0f8dc01f3165e741b711572af2d83fSteven Toth 98606658292a0f8dc01f3165e741b711572af2d83fSteven Toth if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing) 99606658292a0f8dc01f3165e741b711572af2d83fSteven Toth bug++; 100606658292a0f8dc01f3165e741b711572af2d83fSteven Toth 101606658292a0f8dc01f3165e741b711572af2d83fSteven Toth if (bug) { 10299b73d38fa014bcf0f08557cf716907eceffaa1cSteven Toth saa_debug = 0xffff; /* Ensure we get the bus dump */ 103606658292a0f8dc01f3165e741b711572af2d83fSteven Toth saa7164_bus_dump(dev); 10499b73d38fa014bcf0f08557cf716907eceffaa1cSteven Toth saa_debug = 1024; /* Ensure we get the bus dump */ 105606658292a0f8dc01f3165e741b711572af2d83fSteven Toth BUG(); 106606658292a0f8dc01f3165e741b711572af2d83fSteven Toth } 107443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 108443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 109bc25068495b110fcdf35a22f43d32637e99fd018Steven Tothvoid saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m, 110bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth void *buf) 111443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 112443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "Dumping msg structure:\n"); 113443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .id = %d\n", m->id); 114443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .flags = 0x%x\n", m->flags); 115443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .size = 0x%x\n", m->size); 116443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .command = 0x%x\n", m->command); 117443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .controlselector = 0x%x\n", m->controlselector); 118443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .seqno = %d\n", m->seqno); 119443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) 120443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, " .buffer (ignored)\n"); 121443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 122443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 123443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* 124443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Places a command or a response on the bus. The implementation does not 125443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * know if it is a command or a response it just places the data on the 1264d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab * bus depending on the bus information given in the struct tmComResBusInfo 127443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * structure. If the command or response does not fit into the bus ring 128443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * buffer it will be refused. 129443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 130443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Return Value: 131443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * SAA_OK The function executed successfully. 132443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * < 0 One or more members are not initialized. 133443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 134bc25068495b110fcdf35a22f43d32637e99fd018Steven Tothint saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, 135bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth void *buf) 136443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 1374d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResBusInfo *bus = &dev->bus; 138606658292a0f8dc01f3165e741b711572af2d83fSteven Toth u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp; 139443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u32 new_swp, space_rem; 140443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret = SAA_ERR_BAD_PARAMETER; 141443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 142443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (!msg) { 143443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() !msg\n", __func__); 144443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BAD_PARAMETER; 145443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 146443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 147443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s()\n", __func__); 1482e732d64416b243883f753e4a00960c3f3709317Steven Toth 149606658292a0f8dc01f3165e741b711572af2d83fSteven Toth saa7164_bus_verify(dev); 150443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 151443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->size = cpu_to_le16(msg->size); 152773ddbd228dc16a4829836e1dc16383e44c8575eDan Carpenter msg->command = cpu_to_le32(msg->command); 153443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->controlselector = cpu_to_le16(msg->controlselector); 154443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 155443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (msg->size > dev->bus.m_wMaxReqSize) { 156443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", 157443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__); 158443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BAD_PARAMETER; 159443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 160443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 16161ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe if ((msg->size > 0) && (buf == NULL)) { 162443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Missing message buffer\n", __func__); 163443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return SAA_ERR_BAD_PARAMETER; 164443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 165443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 166443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Lock the bus from any other access */ 167443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&bus->lock); 168443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 169443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_write = sizeof(*msg) + msg->size; 170606658292a0f8dc01f3165e741b711572af2d83fSteven Toth free_write_space = 0; 171443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth timeout = SAA_BUS_TIMEOUT; 172606658292a0f8dc01f3165e741b711572af2d83fSteven Toth curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos)); 173606658292a0f8dc01f3165e741b711572af2d83fSteven Toth curr_swp = le32_to_cpu(saa7164_readl(bus->m_dwSetWritePos)); 174443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 175443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Deal with ring wrapping issues */ 176443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_srp > curr_swp) 177443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Deal with the wrapped ring */ 178606658292a0f8dc01f3165e741b711572af2d83fSteven Toth free_write_space = curr_srp - curr_swp; 179606658292a0f8dc01f3165e741b711572af2d83fSteven Toth else 180606658292a0f8dc01f3165e741b711572af2d83fSteven Toth /* The ring has not wrapped yet */ 181606658292a0f8dc01f3165e741b711572af2d83fSteven Toth free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp; 182443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 183443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__, 184443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_write); 185443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 186606658292a0f8dc01f3165e741b711572af2d83fSteven Toth dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__, 187606658292a0f8dc01f3165e741b711572af2d83fSteven Toth free_write_space); 188443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 189443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp); 190443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp); 191443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 192443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Process the msg and write the content onto the bus */ 193606658292a0f8dc01f3165e741b711572af2d83fSteven Toth while (bytes_to_write >= free_write_space) { 194443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 195443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (timeout-- == 0) { 196443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() bus timeout\n", __func__); 197443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_NO_RESOURCES; 198443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 199443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 200443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 201443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* TODO: Review this delay, efficient? */ 202443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Wait, allowing the hardware fetch time */ 203443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mdelay(1); 204443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 205443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Check the space usage again */ 206606658292a0f8dc01f3165e741b711572af2d83fSteven Toth curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos)); 207443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 208443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Deal with ring wrapping issues */ 209443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_srp > curr_swp) 210443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Deal with the wrapped ring */ 211606658292a0f8dc01f3165e741b711572af2d83fSteven Toth free_write_space = curr_srp - curr_swp; 212606658292a0f8dc01f3165e741b711572af2d83fSteven Toth else 213606658292a0f8dc01f3165e741b711572af2d83fSteven Toth /* Read didn't wrap around the buffer */ 214606658292a0f8dc01f3165e741b711572af2d83fSteven Toth free_write_space = (curr_srp + bus->m_dwSizeSetRing) - 215443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth curr_swp; 216443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 217443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 218443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 219443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate the new write position */ 220443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_swp = curr_swp + bytes_to_write; 221443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 222443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); 223443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__, 224443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bus->m_dwSizeSetRing); 225443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 226443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Mental Note: line 462 tmmhComResBusPCIe.cpp */ 227443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 228443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Check if we're going to wrap again */ 229443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (new_swp > bus->m_dwSizeSetRing) { 230443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 231443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Ring wraps */ 232443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_swp -= bus->m_dwSizeSetRing; 233443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 234443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem = bus->m_dwSizeSetRing - curr_swp; 235443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 236443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() space_rem = %x\n", __func__, 237443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem); 238443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 239207b42c492cc335806957c139381eb260a808837Steven Toth dprintk(DBGLVL_BUS, "%s() sizeof(*msg) = %d\n", __func__, 240207b42c492cc335806957c139381eb260a808837Steven Toth (u32)sizeof(*msg)); 241443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 242443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (space_rem < sizeof(*msg)) { 243443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() tr4\n", __func__); 244443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 245443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Split the msg into pieces as the ring wraps */ 246606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem); 247606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem, 248443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg) - space_rem); 249443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 250606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem, 251443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth buf, msg->size); 252443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 253443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else if (space_rem == sizeof(*msg)) { 254443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() tr5\n", __func__); 255443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 256443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Additional data at the beginning of the ring */ 257606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 258606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing, buf, msg->size); 259443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 260443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else { 261443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Additional data wraps around the ring */ 262606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 263443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (msg->size > 0) { 264606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing + curr_swp + 265443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg), buf, space_rem - 266443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg)); 267606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing, (u8 *)buf + 268443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem - sizeof(*msg), 269443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_write - space_rem); 270443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 271443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 272443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 273443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 274443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } /* (new_swp > bus->m_dwSizeSetRing) */ 275443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else { 276443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() tr6\n", __func__); 277443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 278443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* The ring buffer doesn't wrap, two simple copies */ 279606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg)); 280606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf, 281443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->size); 282443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 283443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 284443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp); 285443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 286443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Update the bus write position */ 287606658292a0f8dc01f3165e741b711572af2d83fSteven Toth saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp)); 288443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_OK; 289443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 290443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothout: 291606658292a0f8dc01f3165e741b711572af2d83fSteven Toth saa7164_bus_dump(dev); 292443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&bus->lock); 293606658292a0f8dc01f3165e741b711572af2d83fSteven Toth saa7164_bus_verify(dev); 294443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 295443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 296443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 297443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth/* 298443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Receive a command or a response from the bus. The implementation does not 299443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * know if it is a command or a response it simply dequeues the data, 300bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth * depending on the bus information given in the struct tmComResBusInfo 301bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth * structure. 302443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 303443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * Return Value: 304443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * 0 The function executed successfully. 305443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * < 0 One or more members are not initialized. 306443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 307bc25068495b110fcdf35a22f43d32637e99fd018Steven Tothint saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, 308bc25068495b110fcdf35a22f43d32637e99fd018Steven Toth void *buf, int peekonly) 309443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth{ 3104d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResBusInfo *bus = &dev->bus; 311443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth u32 bytes_to_read, write_distance, curr_grp, curr_gwp, 312443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp, buf_size, space_rem; 3134d270cfb36683f623f2c23f96b695deb1812476eMauro Carvalho Chehab struct tmComResInfo msg_tmp; 314443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth int ret = SAA_ERR_BAD_PARAMETER; 315443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 316606658292a0f8dc01f3165e741b711572af2d83fSteven Toth saa7164_bus_verify(dev); 3172e732d64416b243883f753e4a00960c3f3709317Steven Toth 31861ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe if (msg == NULL) 319443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 320443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 321443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (msg->size > dev->bus.m_wMaxReqSize) { 322443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n", 323443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__); 324443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 325443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 326443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 32761ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) { 328443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR 329443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "%s() Missing msg buf, size should be %d bytes\n", 330443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth __func__, msg->size); 331443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 332443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 333443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 334443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_lock(&bus->lock); 335443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 336443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Peek the bus to see if a msg exists, if it's not what we're expecting 337443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth * then return cleanly else read the message from the bus. 338443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth */ 339606658292a0f8dc01f3165e741b711572af2d83fSteven Toth curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos)); 340606658292a0f8dc01f3165e741b711572af2d83fSteven Toth curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos)); 341443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 342443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_gwp == curr_grp) { 343443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_EMPTY; 344443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 345443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 346443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 347443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_read = sizeof(*msg); 348443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 349443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate write distance to current read position */ 350443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = 0; 351443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_gwp >= curr_grp) 352443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Write doesn't wrap around the ring */ 353443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = curr_gwp - curr_grp; 354443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 355443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Write wraps around the ring */ 356443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; 357443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 358443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (bytes_to_read > write_distance) { 359443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() No message/response found\n", __func__); 360443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_INVALID_COMMAND; 361443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 362443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 363443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 364443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate the new read position */ 365443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp = curr_grp + bytes_to_read; 366443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (new_grp > bus->m_dwSizeGetRing) { 367443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 368443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Ring wraps */ 369443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp -= bus->m_dwSizeGetRing; 370443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem = bus->m_dwSizeGetRing - curr_grp; 371443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 372606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem); 373606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing, 374443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_read - space_rem); 375443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 376443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else { 377443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* No wrapping */ 378606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read); 379443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 380443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 381443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* No need to update the read positions, because this was a peek */ 382443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* If the caller specifically want to peek, return */ 383443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (peekonly) { 384606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(msg, &msg_tmp, sizeof(*msg)); 385443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto peekout; 386443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 387443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 388443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Check if the command/response matches what is expected */ 389443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if ((msg_tmp.id != msg->id) || (msg_tmp.command != msg->command) || 390443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (msg_tmp.controlselector != msg->controlselector) || 391443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth (msg_tmp.seqno != msg->seqno) || (msg_tmp.size != msg->size)) { 392443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 393443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__); 394443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth saa7164_bus_dumpmsg(dev, msg, buf); 39561ca1500c5ee04f2be34a4f58bb9baed0214b7a9Peter Huewe saa7164_bus_dumpmsg(dev, &msg_tmp, NULL); 396443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_INVALID_COMMAND; 397443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 398443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 399443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 400443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Get the actual command and response from the bus */ 401443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth buf_size = msg->size; 402443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 403443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bytes_to_read = sizeof(*msg) + msg->size; 404443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate write distance to current read position */ 405443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = 0; 406443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (curr_gwp >= curr_grp) 407443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Write doesn't wrap around the ring */ 408443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = curr_gwp - curr_grp; 409443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth else 410443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Write wraps around the ring */ 411443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; 412443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 413443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (bytes_to_read > write_distance) { 414443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth printk(KERN_ERR "%s() Invalid bus state, missing msg " 415443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth "or mangled ring, faulty H/W / bad code?\n", __func__); 416443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_ERR_INVALID_COMMAND; 417443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth goto out; 418443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 419443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 420443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Calculate the new read position */ 421443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp = curr_grp + bytes_to_read; 422443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (new_grp > bus->m_dwSizeGetRing) { 423443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 424443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Ring wraps */ 425443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth new_grp -= bus->m_dwSizeGetRing; 426443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem = bus->m_dwSizeGetRing - curr_grp; 427443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 428443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (space_rem < sizeof(*msg)) { 429443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* msg wraps around the ring */ 430606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem); 431606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing, 432443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg) - space_rem); 433443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) 434606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) - 435443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem, buf_size); 436443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 437443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else if (space_rem == sizeof(*msg)) { 438606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 439443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) 440443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth memcpy(buf, bus->m_pdwGetRing, buf_size); 441443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else { 442443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Additional data wraps around the ring */ 443606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 444443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) { 445606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(buf, bus->m_pdwGetRing + curr_grp + 446443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth sizeof(*msg), space_rem - sizeof(*msg)); 447606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(buf + space_rem - sizeof(*msg), 448443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth bus->m_pdwGetRing, bytes_to_read - 449443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth space_rem); 450443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 451443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 452443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 453443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 454443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } else { 455443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* No wrapping */ 456606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg)); 457443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth if (buf) 458606658292a0f8dc01f3165e741b711572af2d83fSteven Toth memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg), 459443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth buf_size); 460443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth } 461443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 462443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth /* Update the read positions, adjusting the ring */ 463606658292a0f8dc01f3165e741b711572af2d83fSteven Toth saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp)); 464443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 465443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothpeekout: 466443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->size = le16_to_cpu(msg->size); 467773ddbd228dc16a4829836e1dc16383e44c8575eDan Carpenter msg->command = le32_to_cpu(msg->command); 468443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth msg->controlselector = le16_to_cpu(msg->controlselector); 469443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth ret = SAA_OK; 470443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Tothout: 471443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth mutex_unlock(&bus->lock); 472606658292a0f8dc01f3165e741b711572af2d83fSteven Toth saa7164_bus_verify(dev); 473443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth return ret; 474443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth} 475443c1228d50518f3c550e1fef490a2c9d9246ce7Steven Toth 476