11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2b5e47729SStefan Richter /* 3b5e47729SStefan Richter * nosy - Snoop mode driver for TI PCILynx 1394 controllers 4b5e47729SStefan Richter * Copyright (C) 2002-2007 Kristian Høgsberg 528646821SStefan Richter */ 628646821SStefan Richter 77429b17dSStefan Richter #include <linux/device.h> 828646821SStefan Richter #include <linux/errno.h> 928646821SStefan Richter #include <linux/fs.h> 10b5e47729SStefan Richter #include <linux/init.h> 11b5e47729SStefan Richter #include <linux/interrupt.h> 12b5e47729SStefan Richter #include <linux/io.h> 13b5e47729SStefan Richter #include <linux/kernel.h> 14424d66ceSStefan Richter #include <linux/kref.h> 1528646821SStefan Richter #include <linux/miscdevice.h> 16b5e47729SStefan Richter #include <linux/module.h> 17424d66ceSStefan Richter #include <linux/mutex.h> 18b5e47729SStefan Richter #include <linux/pci.h> 19b5e47729SStefan Richter #include <linux/poll.h> 20b5e47729SStefan Richter #include <linux/sched.h> /* required for linux/wait.h */ 21b5e47729SStefan Richter #include <linux/slab.h> 22b5e47729SStefan Richter #include <linux/spinlock.h> 232ae4b6b2SAmitoj Kaur Chawla #include <linux/time64.h> 24b5e47729SStefan Richter #include <linux/timex.h> 25b5e47729SStefan Richter #include <linux/uaccess.h> 26b5e47729SStefan Richter #include <linux/wait.h> 27e894d1d7Ssantosh nayak #include <linux/dma-mapping.h> 2860063497SArun Sharma #include <linux/atomic.h> 29b5e47729SStefan Richter #include <asm/byteorder.h> 3028646821SStefan Richter 3128646821SStefan Richter #include "nosy.h" 3228646821SStefan Richter #include "nosy-user.h" 3328646821SStefan Richter 3428646821SStefan Richter #define TCODE_PHY_PACKET 0x10 3528646821SStefan Richter #define PCI_DEVICE_ID_TI_PCILYNX 0x8000 3628646821SStefan Richter 37b5e47729SStefan Richter static char driver_name[] = KBUILD_MODNAME; 3828646821SStefan Richter 3928646821SStefan Richter /* this is the physical layout of a PCL, its size is 128 bytes */ 4028646821SStefan Richter struct pcl { 41fd8c8d46SStefan Richter __le32 next; 42fd8c8d46SStefan Richter __le32 async_error_next; 4328646821SStefan Richter u32 user_data; 44fd8c8d46SStefan Richter __le32 pcl_status; 45fd8c8d46SStefan Richter __le32 remaining_transfer_count; 46fd8c8d46SStefan Richter __le32 next_data_buffer; 4728646821SStefan Richter struct { 48fd8c8d46SStefan Richter __le32 control; 49fd8c8d46SStefan Richter __le32 pointer; 50fd8c8d46SStefan Richter } buffer[13]; 51fd8c8d46SStefan Richter }; 5228646821SStefan Richter 5328646821SStefan Richter struct packet { 54b5e47729SStefan Richter unsigned int length; 55c38e7e21SGustavo A. R. Silva char data[]; 5628646821SStefan Richter }; 5728646821SStefan Richter 5828646821SStefan Richter struct packet_buffer { 5928646821SStefan Richter char *data; 6028646821SStefan Richter size_t capacity; 6128646821SStefan Richter long total_packet_count, lost_packet_count; 6228646821SStefan Richter atomic_t size; 6328646821SStefan Richter struct packet *head, *tail; 6428646821SStefan Richter wait_queue_head_t wait; 6528646821SStefan Richter }; 6628646821SStefan Richter 6728646821SStefan Richter struct pcilynx { 6828646821SStefan Richter struct pci_dev *pci_device; 69c89db7b8SStefan Richter __iomem char *registers; 7028646821SStefan Richter 7128646821SStefan Richter struct pcl *rcv_start_pcl, *rcv_pcl; 72fd8c8d46SStefan Richter __le32 *rcv_buffer; 7328646821SStefan Richter 7428646821SStefan Richter dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; 7528646821SStefan Richter 7628646821SStefan Richter spinlock_t client_list_lock; 7728646821SStefan Richter struct list_head client_list; 7828646821SStefan Richter 7928646821SStefan Richter struct miscdevice misc; 80424d66ceSStefan Richter struct list_head link; 81424d66ceSStefan Richter struct kref kref; 8228646821SStefan Richter }; 8328646821SStefan Richter 84424d66ceSStefan Richter static inline struct pcilynx * 85424d66ceSStefan Richter lynx_get(struct pcilynx *lynx) 86424d66ceSStefan Richter { 87424d66ceSStefan Richter kref_get(&lynx->kref); 88424d66ceSStefan Richter 89424d66ceSStefan Richter return lynx; 90424d66ceSStefan Richter } 91424d66ceSStefan Richter 92424d66ceSStefan Richter static void 93424d66ceSStefan Richter lynx_release(struct kref *kref) 94424d66ceSStefan Richter { 95424d66ceSStefan Richter kfree(container_of(kref, struct pcilynx, kref)); 96424d66ceSStefan Richter } 97424d66ceSStefan Richter 98424d66ceSStefan Richter static inline void 99424d66ceSStefan Richter lynx_put(struct pcilynx *lynx) 100424d66ceSStefan Richter { 101424d66ceSStefan Richter kref_put(&lynx->kref, lynx_release); 102424d66ceSStefan Richter } 103424d66ceSStefan Richter 10428646821SStefan Richter struct client { 10528646821SStefan Richter struct pcilynx *lynx; 106c7b2a99cSStefan Richter u32 tcode_mask; 10728646821SStefan Richter struct packet_buffer buffer; 10828646821SStefan Richter struct list_head link; 10928646821SStefan Richter }; 11028646821SStefan Richter 111424d66ceSStefan Richter static DEFINE_MUTEX(card_mutex); 112424d66ceSStefan Richter static LIST_HEAD(card_list); 11328646821SStefan Richter 11428646821SStefan Richter static int 11528646821SStefan Richter packet_buffer_init(struct packet_buffer *buffer, size_t capacity) 11628646821SStefan Richter { 11728646821SStefan Richter buffer->data = kmalloc(capacity, GFP_KERNEL); 11828646821SStefan Richter if (buffer->data == NULL) 11928646821SStefan Richter return -ENOMEM; 12028646821SStefan Richter buffer->head = (struct packet *) buffer->data; 12128646821SStefan Richter buffer->tail = (struct packet *) buffer->data; 12228646821SStefan Richter buffer->capacity = capacity; 12328646821SStefan Richter buffer->lost_packet_count = 0; 12428646821SStefan Richter atomic_set(&buffer->size, 0); 12528646821SStefan Richter init_waitqueue_head(&buffer->wait); 12628646821SStefan Richter 12728646821SStefan Richter return 0; 12828646821SStefan Richter } 12928646821SStefan Richter 13028646821SStefan Richter static void 13128646821SStefan Richter packet_buffer_destroy(struct packet_buffer *buffer) 13228646821SStefan Richter { 13328646821SStefan Richter kfree(buffer->data); 13428646821SStefan Richter } 13528646821SStefan Richter 13628646821SStefan Richter static int 137c89db7b8SStefan Richter packet_buffer_get(struct client *client, char __user *data, size_t user_length) 13828646821SStefan Richter { 139424d66ceSStefan Richter struct packet_buffer *buffer = &client->buffer; 14028646821SStefan Richter size_t length; 14128646821SStefan Richter char *end; 14228646821SStefan Richter 14328646821SStefan Richter if (wait_event_interruptible(buffer->wait, 144424d66ceSStefan Richter atomic_read(&buffer->size) > 0) || 145424d66ceSStefan Richter list_empty(&client->lynx->link)) 14628646821SStefan Richter return -ERESTARTSYS; 14728646821SStefan Richter 148424d66ceSStefan Richter if (atomic_read(&buffer->size) == 0) 149424d66ceSStefan Richter return -ENODEV; 150424d66ceSStefan Richter 15128646821SStefan Richter /* FIXME: Check length <= user_length. */ 15228646821SStefan Richter 15328646821SStefan Richter end = buffer->data + buffer->capacity; 15428646821SStefan Richter length = buffer->head->length; 15528646821SStefan Richter 15628646821SStefan Richter if (&buffer->head->data[length] < end) { 15728646821SStefan Richter if (copy_to_user(data, buffer->head->data, length)) 15828646821SStefan Richter return -EFAULT; 15928646821SStefan Richter buffer->head = (struct packet *) &buffer->head->data[length]; 160b5e47729SStefan Richter } else { 16128646821SStefan Richter size_t split = end - buffer->head->data; 16228646821SStefan Richter 16328646821SStefan Richter if (copy_to_user(data, buffer->head->data, split)) 16428646821SStefan Richter return -EFAULT; 16528646821SStefan Richter if (copy_to_user(data + split, buffer->data, length - split)) 16628646821SStefan Richter return -EFAULT; 16728646821SStefan Richter buffer->head = (struct packet *) &buffer->data[length - split]; 16828646821SStefan Richter } 16928646821SStefan Richter 170b5e47729SStefan Richter /* 171b5e47729SStefan Richter * Decrease buffer->size as the last thing, since this is what 17228646821SStefan Richter * keeps the interrupt from overwriting the packet we are 173b5e47729SStefan Richter * retrieving from the buffer. 174b5e47729SStefan Richter */ 17528646821SStefan Richter atomic_sub(sizeof(struct packet) + length, &buffer->size); 17628646821SStefan Richter 17728646821SStefan Richter return length; 17828646821SStefan Richter } 17928646821SStefan Richter 18028646821SStefan Richter static void 18128646821SStefan Richter packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length) 18228646821SStefan Richter { 18328646821SStefan Richter char *end; 18428646821SStefan Richter 18528646821SStefan Richter buffer->total_packet_count++; 18628646821SStefan Richter 18728646821SStefan Richter if (buffer->capacity < 18828646821SStefan Richter atomic_read(&buffer->size) + sizeof(struct packet) + length) { 18928646821SStefan Richter buffer->lost_packet_count++; 19028646821SStefan Richter return; 19128646821SStefan Richter } 19228646821SStefan Richter 19328646821SStefan Richter end = buffer->data + buffer->capacity; 19428646821SStefan Richter buffer->tail->length = length; 19528646821SStefan Richter 19628646821SStefan Richter if (&buffer->tail->data[length] < end) { 19728646821SStefan Richter memcpy(buffer->tail->data, data, length); 19828646821SStefan Richter buffer->tail = (struct packet *) &buffer->tail->data[length]; 199b5e47729SStefan Richter } else { 20028646821SStefan Richter size_t split = end - buffer->tail->data; 20128646821SStefan Richter 20228646821SStefan Richter memcpy(buffer->tail->data, data, split); 20328646821SStefan Richter memcpy(buffer->data, data + split, length - split); 20428646821SStefan Richter buffer->tail = (struct packet *) &buffer->data[length - split]; 20528646821SStefan Richter } 20628646821SStefan Richter 20728646821SStefan Richter /* Finally, adjust buffer size and wake up userspace reader. */ 20828646821SStefan Richter 20928646821SStefan Richter atomic_add(sizeof(struct packet) + length, &buffer->size); 21028646821SStefan Richter wake_up_interruptible(&buffer->wait); 21128646821SStefan Richter } 21228646821SStefan Richter 21328646821SStefan Richter static inline void 21428646821SStefan Richter reg_write(struct pcilynx *lynx, int offset, u32 data) 21528646821SStefan Richter { 21628646821SStefan Richter writel(data, lynx->registers + offset); 21728646821SStefan Richter } 21828646821SStefan Richter 21928646821SStefan Richter static inline u32 22028646821SStefan Richter reg_read(struct pcilynx *lynx, int offset) 22128646821SStefan Richter { 22228646821SStefan Richter return readl(lynx->registers + offset); 22328646821SStefan Richter } 22428646821SStefan Richter 22528646821SStefan Richter static inline void 22628646821SStefan Richter reg_set_bits(struct pcilynx *lynx, int offset, u32 mask) 22728646821SStefan Richter { 22828646821SStefan Richter reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); 22928646821SStefan Richter } 23028646821SStefan Richter 231b5e47729SStefan Richter /* 232b5e47729SStefan Richter * Maybe the pcl programs could be set up to just append data instead 233b5e47729SStefan Richter * of using a whole packet. 234b5e47729SStefan Richter */ 23528646821SStefan Richter static inline void 236b5e47729SStefan Richter run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, 237b5e47729SStefan Richter int dmachan) 23828646821SStefan Richter { 23928646821SStefan Richter reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus); 24028646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, 24128646821SStefan Richter DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); 24228646821SStefan Richter } 24328646821SStefan Richter 24428646821SStefan Richter static int 24528646821SStefan Richter set_phy_reg(struct pcilynx *lynx, int addr, int val) 24628646821SStefan Richter { 24728646821SStefan Richter if (addr > 15) { 2487429b17dSStefan Richter dev_err(&lynx->pci_device->dev, 2497429b17dSStefan Richter "PHY register address %d out of range\n", addr); 25028646821SStefan Richter return -1; 25128646821SStefan Richter } 25228646821SStefan Richter if (val > 0xff) { 2537429b17dSStefan Richter dev_err(&lynx->pci_device->dev, 2547429b17dSStefan Richter "PHY register value %d out of range\n", val); 25528646821SStefan Richter return -1; 25628646821SStefan Richter } 25728646821SStefan Richter reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | 25828646821SStefan Richter LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val)); 25928646821SStefan Richter 26028646821SStefan Richter return 0; 26128646821SStefan Richter } 26228646821SStefan Richter 26328646821SStefan Richter static int 26428646821SStefan Richter nosy_open(struct inode *inode, struct file *file) 26528646821SStefan Richter { 26628646821SStefan Richter int minor = iminor(inode); 26755e77c06SStefan Richter struct client *client; 268424d66ceSStefan Richter struct pcilynx *tmp, *lynx = NULL; 26928646821SStefan Richter 270424d66ceSStefan Richter mutex_lock(&card_mutex); 271424d66ceSStefan Richter list_for_each_entry(tmp, &card_list, link) 272424d66ceSStefan Richter if (tmp->misc.minor == minor) { 273424d66ceSStefan Richter lynx = lynx_get(tmp); 274424d66ceSStefan Richter break; 275424d66ceSStefan Richter } 276424d66ceSStefan Richter mutex_unlock(&card_mutex); 277424d66ceSStefan Richter if (lynx == NULL) 27828646821SStefan Richter return -ENODEV; 27928646821SStefan Richter 28055e77c06SStefan Richter client = kmalloc(sizeof *client, GFP_KERNEL); 28155e77c06SStefan Richter if (client == NULL) 282424d66ceSStefan Richter goto fail; 28355e77c06SStefan Richter 28455e77c06SStefan Richter client->tcode_mask = ~0; 285424d66ceSStefan Richter client->lynx = lynx; 28655e77c06SStefan Richter INIT_LIST_HEAD(&client->link); 28755e77c06SStefan Richter 288424d66ceSStefan Richter if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) 289424d66ceSStefan Richter goto fail; 29055e77c06SStefan Richter 29155e77c06SStefan Richter file->private_data = client; 29255e77c06SStefan Richter 293c5bf68feSKirill Smelkov return stream_open(inode, file); 294424d66ceSStefan Richter fail: 295424d66ceSStefan Richter kfree(client); 296424d66ceSStefan Richter lynx_put(lynx); 297424d66ceSStefan Richter 298424d66ceSStefan Richter return -ENOMEM; 29928646821SStefan Richter } 30028646821SStefan Richter 30128646821SStefan Richter static int 30228646821SStefan Richter nosy_release(struct inode *inode, struct file *file) 30328646821SStefan Richter { 30455e77c06SStefan Richter struct client *client = file->private_data; 305424d66ceSStefan Richter struct pcilynx *lynx = client->lynx; 30655e77c06SStefan Richter 307424d66ceSStefan Richter spin_lock_irq(&lynx->client_list_lock); 30855e77c06SStefan Richter list_del_init(&client->link); 309424d66ceSStefan Richter spin_unlock_irq(&lynx->client_list_lock); 31055e77c06SStefan Richter 31155e77c06SStefan Richter packet_buffer_destroy(&client->buffer); 31255e77c06SStefan Richter kfree(client); 313424d66ceSStefan Richter lynx_put(lynx); 31428646821SStefan Richter 31528646821SStefan Richter return 0; 31628646821SStefan Richter } 31728646821SStefan Richter 318afc9a42bSAl Viro static __poll_t 31928646821SStefan Richter nosy_poll(struct file *file, poll_table *pt) 32028646821SStefan Richter { 32128646821SStefan Richter struct client *client = file->private_data; 322afc9a42bSAl Viro __poll_t ret = 0; 32328646821SStefan Richter 32428646821SStefan Richter poll_wait(file, &client->buffer.wait, pt); 32528646821SStefan Richter 32628646821SStefan Richter if (atomic_read(&client->buffer.size) > 0) 327a9a08845SLinus Torvalds ret = EPOLLIN | EPOLLRDNORM; 328424d66ceSStefan Richter 329424d66ceSStefan Richter if (list_empty(&client->lynx->link)) 330a9a08845SLinus Torvalds ret |= EPOLLHUP; 331424d66ceSStefan Richter 332424d66ceSStefan Richter return ret; 33328646821SStefan Richter } 33428646821SStefan Richter 33528646821SStefan Richter static ssize_t 336c89db7b8SStefan Richter nosy_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) 33728646821SStefan Richter { 33828646821SStefan Richter struct client *client = file->private_data; 33928646821SStefan Richter 340424d66ceSStefan Richter return packet_buffer_get(client, buffer, count); 34128646821SStefan Richter } 34228646821SStefan Richter 343c7b2a99cSStefan Richter static long 344c7b2a99cSStefan Richter nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 34528646821SStefan Richter { 34628646821SStefan Richter struct client *client = file->private_data; 347c7b2a99cSStefan Richter spinlock_t *client_list_lock = &client->lynx->client_list_lock; 34828646821SStefan Richter struct nosy_stats stats; 34928646821SStefan Richter 350b5e47729SStefan Richter switch (cmd) { 351b5e47729SStefan Richter case NOSY_IOC_GET_STATS: 352c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 35328646821SStefan Richter stats.total_packet_count = client->buffer.total_packet_count; 35428646821SStefan Richter stats.lost_packet_count = client->buffer.lost_packet_count; 355c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 356c7b2a99cSStefan Richter 357c89db7b8SStefan Richter if (copy_to_user((void __user *) arg, &stats, sizeof stats)) 35828646821SStefan Richter return -EFAULT; 35928646821SStefan Richter else 36028646821SStefan Richter return 0; 36128646821SStefan Richter 36228646821SStefan Richter case NOSY_IOC_START: 36355e77c06SStefan Richter spin_lock_irq(client_list_lock); 36455e77c06SStefan Richter list_add_tail(&client->link, &client->lynx->client_list); 36555e77c06SStefan Richter spin_unlock_irq(client_list_lock); 36655e77c06SStefan Richter 36728646821SStefan Richter return 0; 36828646821SStefan Richter 36928646821SStefan Richter case NOSY_IOC_STOP: 37055e77c06SStefan Richter spin_lock_irq(client_list_lock); 37155e77c06SStefan Richter list_del_init(&client->link); 37255e77c06SStefan Richter spin_unlock_irq(client_list_lock); 37355e77c06SStefan Richter 37428646821SStefan Richter return 0; 37528646821SStefan Richter 37628646821SStefan Richter case NOSY_IOC_FILTER: 377c7b2a99cSStefan Richter spin_lock_irq(client_list_lock); 37828646821SStefan Richter client->tcode_mask = arg; 379c7b2a99cSStefan Richter spin_unlock_irq(client_list_lock); 38055e77c06SStefan Richter 38128646821SStefan Richter return 0; 38228646821SStefan Richter 38328646821SStefan Richter default: 38428646821SStefan Richter return -EINVAL; 38528646821SStefan Richter /* Flush buffer, configure filter. */ 38628646821SStefan Richter } 38728646821SStefan Richter } 38828646821SStefan Richter 389b5e47729SStefan Richter static const struct file_operations nosy_ops = { 39028646821SStefan Richter .owner = THIS_MODULE, 39128646821SStefan Richter .read = nosy_read, 392c7b2a99cSStefan Richter .unlocked_ioctl = nosy_ioctl, 39328646821SStefan Richter .poll = nosy_poll, 39428646821SStefan Richter .open = nosy_open, 39528646821SStefan Richter .release = nosy_release, 39628646821SStefan Richter }; 39728646821SStefan Richter 39828646821SStefan Richter #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ 39928646821SStefan Richter 40028646821SStefan Richter static void 401685c3f80SStefan Richter packet_irq_handler(struct pcilynx *lynx) 40228646821SStefan Richter { 40328646821SStefan Richter struct client *client; 4042ae4b6b2SAmitoj Kaur Chawla u32 tcode_mask, tcode, timestamp; 40528646821SStefan Richter size_t length; 4062ae4b6b2SAmitoj Kaur Chawla struct timespec64 ts64; 40728646821SStefan Richter 40828646821SStefan Richter /* FIXME: Also report rcv_speed. */ 40928646821SStefan Richter 410fd8c8d46SStefan Richter length = __le32_to_cpu(lynx->rcv_pcl->pcl_status) & 0x00001fff; 411fd8c8d46SStefan Richter tcode = __le32_to_cpu(lynx->rcv_buffer[1]) >> 4 & 0xf; 41228646821SStefan Richter 4132ae4b6b2SAmitoj Kaur Chawla ktime_get_real_ts64(&ts64); 4142ae4b6b2SAmitoj Kaur Chawla timestamp = ts64.tv_nsec / NSEC_PER_USEC; 4152ae4b6b2SAmitoj Kaur Chawla lynx->rcv_buffer[0] = (__force __le32)timestamp; 41628646821SStefan Richter 41728646821SStefan Richter if (length == PHY_PACKET_SIZE) 41828646821SStefan Richter tcode_mask = 1 << TCODE_PHY_PACKET; 41928646821SStefan Richter else 420fd8c8d46SStefan Richter tcode_mask = 1 << tcode; 42128646821SStefan Richter 422685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 42328646821SStefan Richter 424b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 42528646821SStefan Richter if (client->tcode_mask & tcode_mask) 42628646821SStefan Richter packet_buffer_put(&client->buffer, 42728646821SStefan Richter lynx->rcv_buffer, length + 4); 42828646821SStefan Richter 429685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 43028646821SStefan Richter } 43128646821SStefan Richter 43228646821SStefan Richter static void 433685c3f80SStefan Richter bus_reset_irq_handler(struct pcilynx *lynx) 43428646821SStefan Richter { 43528646821SStefan Richter struct client *client; 436384fbb96STina Ruchandani struct timespec64 ts64; 437384fbb96STina Ruchandani u32 timestamp; 43828646821SStefan Richter 439384fbb96STina Ruchandani ktime_get_real_ts64(&ts64); 440384fbb96STina Ruchandani timestamp = ts64.tv_nsec / NSEC_PER_USEC; 44128646821SStefan Richter 442685c3f80SStefan Richter spin_lock(&lynx->client_list_lock); 44328646821SStefan Richter 444b5e47729SStefan Richter list_for_each_entry(client, &lynx->client_list, link) 445384fbb96STina Ruchandani packet_buffer_put(&client->buffer, ×tamp, 4); 44628646821SStefan Richter 447685c3f80SStefan Richter spin_unlock(&lynx->client_list_lock); 44828646821SStefan Richter } 44928646821SStefan Richter 45028646821SStefan Richter static irqreturn_t 45128646821SStefan Richter irq_handler(int irq, void *device) 45228646821SStefan Richter { 453b5e47729SStefan Richter struct pcilynx *lynx = device; 45428646821SStefan Richter u32 pci_int_status; 45528646821SStefan Richter 45628646821SStefan Richter pci_int_status = reg_read(lynx, PCI_INT_STATUS); 45728646821SStefan Richter 45816547667SStefan Richter if (pci_int_status == ~0) 45916547667SStefan Richter /* Card was ejected. */ 46016547667SStefan Richter return IRQ_NONE; 46116547667SStefan Richter 46228646821SStefan Richter if ((pci_int_status & PCI_INT_INT_PEND) == 0) 46328646821SStefan Richter /* Not our interrupt, bail out quickly. */ 46428646821SStefan Richter return IRQ_NONE; 46528646821SStefan Richter 46628646821SStefan Richter if ((pci_int_status & PCI_INT_P1394_INT) != 0) { 46728646821SStefan Richter u32 link_int_status; 46828646821SStefan Richter 46928646821SStefan Richter link_int_status = reg_read(lynx, LINK_INT_STATUS); 47028646821SStefan Richter reg_write(lynx, LINK_INT_STATUS, link_int_status); 47128646821SStefan Richter 47228646821SStefan Richter if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0) 473685c3f80SStefan Richter bus_reset_irq_handler(lynx); 47428646821SStefan Richter } 47528646821SStefan Richter 47628646821SStefan Richter /* Clear the PCI_INT_STATUS register only after clearing the 47728646821SStefan Richter * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will 47828646821SStefan Richter * be set again immediately. */ 47928646821SStefan Richter 48028646821SStefan Richter reg_write(lynx, PCI_INT_STATUS, pci_int_status); 48128646821SStefan Richter 48228646821SStefan Richter if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) { 483685c3f80SStefan Richter packet_irq_handler(lynx); 48428646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 48528646821SStefan Richter } 48628646821SStefan Richter 48728646821SStefan Richter return IRQ_HANDLED; 48828646821SStefan Richter } 48928646821SStefan Richter 49028646821SStefan Richter static void 49128646821SStefan Richter remove_card(struct pci_dev *dev) 49228646821SStefan Richter { 493424d66ceSStefan Richter struct pcilynx *lynx = pci_get_drvdata(dev); 494424d66ceSStefan Richter struct client *client; 49528646821SStefan Richter 496424d66ceSStefan Richter mutex_lock(&card_mutex); 497424d66ceSStefan Richter list_del_init(&lynx->link); 498424d66ceSStefan Richter misc_deregister(&lynx->misc); 499424d66ceSStefan Richter mutex_unlock(&card_mutex); 50028646821SStefan Richter 50128646821SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 50228646821SStefan Richter free_irq(lynx->pci_device->irq, lynx); 50328646821SStefan Richter 504424d66ceSStefan Richter spin_lock_irq(&lynx->client_list_lock); 505424d66ceSStefan Richter list_for_each_entry(client, &lynx->client_list, link) 506424d66ceSStefan Richter wake_up_interruptible(&client->buffer.wait); 507424d66ceSStefan Richter spin_unlock_irq(&lynx->client_list_lock); 508424d66ceSStefan Richter 50928646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 51028646821SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 51128646821SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 51228646821SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 51328646821SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 51428646821SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 51528646821SStefan Richter 51628646821SStefan Richter iounmap(lynx->registers); 517b6d9c125SStefan Richter pci_disable_device(dev); 518424d66ceSStefan Richter lynx_put(lynx); 51928646821SStefan Richter } 52028646821SStefan Richter 52128646821SStefan Richter #define RCV_BUFFER_SIZE (16 * 1024) 52228646821SStefan Richter 52303f94c0fSBill Pemberton static int 52428646821SStefan Richter add_card(struct pci_dev *dev, const struct pci_device_id *unused) 52528646821SStefan Richter { 52628646821SStefan Richter struct pcilynx *lynx; 52728646821SStefan Richter u32 p, end; 528b6d9c125SStefan Richter int ret, i; 52928646821SStefan Richter 530e894d1d7Ssantosh nayak if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { 5317429b17dSStefan Richter dev_err(&dev->dev, 5327429b17dSStefan Richter "DMA address limits not supported for PCILynx hardware\n"); 533b5e47729SStefan Richter return -ENXIO; 534b5e47729SStefan Richter } 535b5e47729SStefan Richter if (pci_enable_device(dev)) { 5367429b17dSStefan Richter dev_err(&dev->dev, "Failed to enable PCILynx hardware\n"); 537b5e47729SStefan Richter return -ENXIO; 538b5e47729SStefan Richter } 53928646821SStefan Richter pci_set_master(dev); 54028646821SStefan Richter 54128646821SStefan Richter lynx = kzalloc(sizeof *lynx, GFP_KERNEL); 542b5e47729SStefan Richter if (lynx == NULL) { 5437429b17dSStefan Richter dev_err(&dev->dev, "Failed to allocate control structure\n"); 544b6d9c125SStefan Richter ret = -ENOMEM; 545b6d9c125SStefan Richter goto fail_disable; 546b5e47729SStefan Richter } 54728646821SStefan Richter lynx->pci_device = dev; 54828646821SStefan Richter pci_set_drvdata(dev, lynx); 54928646821SStefan Richter 55028646821SStefan Richter spin_lock_init(&lynx->client_list_lock); 55128646821SStefan Richter INIT_LIST_HEAD(&lynx->client_list); 552424d66ceSStefan Richter kref_init(&lynx->kref); 55328646821SStefan Richter 5544bdc0d67SChristoph Hellwig lynx->registers = ioremap(pci_resource_start(dev, 0), 55528646821SStefan Richter PCILYNX_MAX_REGISTER); 5566449e31dSAlexey Khoroshilov if (lynx->registers == NULL) { 5576449e31dSAlexey Khoroshilov dev_err(&dev->dev, "Failed to map registers\n"); 5586449e31dSAlexey Khoroshilov ret = -ENOMEM; 5596449e31dSAlexey Khoroshilov goto fail_deallocate_lynx; 5606449e31dSAlexey Khoroshilov } 56128646821SStefan Richter 56228646821SStefan Richter lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, 563b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_start_pcl_bus); 56428646821SStefan Richter lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, 565b5e47729SStefan Richter sizeof(struct pcl), &lynx->rcv_pcl_bus); 566b5e47729SStefan Richter lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, 567b5e47729SStefan Richter RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); 56828646821SStefan Richter if (lynx->rcv_start_pcl == NULL || 56928646821SStefan Richter lynx->rcv_pcl == NULL || 570b5e47729SStefan Richter lynx->rcv_buffer == NULL) { 5717429b17dSStefan Richter dev_err(&dev->dev, "Failed to allocate receive buffer\n"); 572b6d9c125SStefan Richter ret = -ENOMEM; 5736449e31dSAlexey Khoroshilov goto fail_deallocate_buffers; 574b5e47729SStefan Richter } 575fd8c8d46SStefan Richter lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus); 576fd8c8d46SStefan Richter lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID); 577fd8c8d46SStefan Richter lynx->rcv_pcl->async_error_next = cpu_to_le32(PCL_NEXT_INVALID); 57828646821SStefan Richter 57928646821SStefan Richter lynx->rcv_pcl->buffer[0].control = 580fd8c8d46SStefan Richter cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2044); 581fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[0].pointer = 582fd8c8d46SStefan Richter cpu_to_le32(lynx->rcv_buffer_bus + 4); 58328646821SStefan Richter p = lynx->rcv_buffer_bus + 2048; 58428646821SStefan Richter end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; 58528646821SStefan Richter for (i = 1; p < end; i++, p += 2048) { 58628646821SStefan Richter lynx->rcv_pcl->buffer[i].control = 587fd8c8d46SStefan Richter cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2048); 588fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[i].pointer = cpu_to_le32(p); 58928646821SStefan Richter } 590fd8c8d46SStefan Richter lynx->rcv_pcl->buffer[i - 1].control |= cpu_to_le32(PCL_LAST_BUFF); 59128646821SStefan Richter 59228646821SStefan Richter reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); 59328646821SStefan Richter /* Fix buggy cards with autoboot pin not tied low: */ 59428646821SStefan Richter reg_write(lynx, DMA0_CHAN_CTRL, 0); 59528646821SStefan Richter reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24); 59628646821SStefan Richter 59728646821SStefan Richter #if 0 59828646821SStefan Richter /* now, looking for PHY register set */ 59928646821SStefan Richter if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { 60028646821SStefan Richter lynx->phyic.reg_1394a = 1; 60128646821SStefan Richter PRINT(KERN_INFO, lynx->id, 60228646821SStefan Richter "found 1394a conform PHY (using extended register set)"); 60328646821SStefan Richter lynx->phyic.vendor = get_phy_vendorid(lynx); 60428646821SStefan Richter lynx->phyic.product = get_phy_productid(lynx); 60528646821SStefan Richter } else { 60628646821SStefan Richter lynx->phyic.reg_1394a = 0; 60728646821SStefan Richter PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); 60828646821SStefan Richter } 60928646821SStefan Richter #endif 61028646821SStefan Richter 61128646821SStefan Richter /* Setup the general receive FIFO max size. */ 61228646821SStefan Richter reg_write(lynx, FIFO_SIZES, 255); 61328646821SStefan Richter 61428646821SStefan Richter reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); 61528646821SStefan Richter 61628646821SStefan Richter reg_write(lynx, LINK_INT_ENABLE, 61728646821SStefan Richter LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD | 61828646821SStefan Richter LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK | 61928646821SStefan Richter LINK_INT_AT_STUCK | LINK_INT_SNTRJ | 62028646821SStefan Richter LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW | 62128646821SStefan Richter LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW); 62228646821SStefan Richter 62328646821SStefan Richter /* Disable the L flag in self ID packets. */ 62428646821SStefan Richter set_phy_reg(lynx, 4, 0); 62528646821SStefan Richter 62628646821SStefan Richter /* Put this baby into snoop mode */ 62728646821SStefan Richter reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE); 62828646821SStefan Richter 62928646821SStefan Richter run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); 63028646821SStefan Richter 631b5e47729SStefan Richter if (request_irq(dev->irq, irq_handler, IRQF_SHARED, 632b5e47729SStefan Richter driver_name, lynx)) { 6337429b17dSStefan Richter dev_err(&dev->dev, 6347429b17dSStefan Richter "Failed to allocate shared interrupt %d\n", dev->irq); 635b6d9c125SStefan Richter ret = -EIO; 6366449e31dSAlexey Khoroshilov goto fail_deallocate_buffers; 637b5e47729SStefan Richter } 63828646821SStefan Richter 63928646821SStefan Richter lynx->misc.parent = &dev->dev; 64028646821SStefan Richter lynx->misc.minor = MISC_DYNAMIC_MINOR; 64128646821SStefan Richter lynx->misc.name = "nosy"; 64228646821SStefan Richter lynx->misc.fops = &nosy_ops; 643424d66ceSStefan Richter 644424d66ceSStefan Richter mutex_lock(&card_mutex); 645b6d9c125SStefan Richter ret = misc_register(&lynx->misc); 646b6d9c125SStefan Richter if (ret) { 6477429b17dSStefan Richter dev_err(&dev->dev, "Failed to register misc char device\n"); 648424d66ceSStefan Richter mutex_unlock(&card_mutex); 649b6d9c125SStefan Richter goto fail_free_irq; 650b5e47729SStefan Richter } 651424d66ceSStefan Richter list_add_tail(&lynx->link, &card_list); 652424d66ceSStefan Richter mutex_unlock(&card_mutex); 65328646821SStefan Richter 6547429b17dSStefan Richter dev_info(&dev->dev, 6557429b17dSStefan Richter "Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq); 65628646821SStefan Richter 65728646821SStefan Richter return 0; 658b6d9c125SStefan Richter 659b6d9c125SStefan Richter fail_free_irq: 660b6d9c125SStefan Richter reg_write(lynx, PCI_INT_ENABLE, 0); 661b6d9c125SStefan Richter free_irq(lynx->pci_device->irq, lynx); 662b6d9c125SStefan Richter 6636449e31dSAlexey Khoroshilov fail_deallocate_buffers: 664b6d9c125SStefan Richter if (lynx->rcv_start_pcl) 665b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 666b6d9c125SStefan Richter lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); 667b6d9c125SStefan Richter if (lynx->rcv_pcl) 668b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, sizeof(struct pcl), 669b6d9c125SStefan Richter lynx->rcv_pcl, lynx->rcv_pcl_bus); 670b6d9c125SStefan Richter if (lynx->rcv_buffer) 671b6d9c125SStefan Richter pci_free_consistent(lynx->pci_device, PAGE_SIZE, 672b6d9c125SStefan Richter lynx->rcv_buffer, lynx->rcv_buffer_bus); 673b6d9c125SStefan Richter iounmap(lynx->registers); 6746449e31dSAlexey Khoroshilov 6756449e31dSAlexey Khoroshilov fail_deallocate_lynx: 676b6d9c125SStefan Richter kfree(lynx); 677b6d9c125SStefan Richter 678b6d9c125SStefan Richter fail_disable: 679b6d9c125SStefan Richter pci_disable_device(dev); 680b6d9c125SStefan Richter 681b6d9c125SStefan Richter return ret; 68228646821SStefan Richter } 68328646821SStefan Richter 6847eeb7418SBill Pemberton static struct pci_device_id pci_table[] = { 68528646821SStefan Richter { 68628646821SStefan Richter .vendor = PCI_VENDOR_ID_TI, 68728646821SStefan Richter .device = PCI_DEVICE_ID_TI_PCILYNX, 68828646821SStefan Richter .subvendor = PCI_ANY_ID, 68928646821SStefan Richter .subdevice = PCI_ANY_ID, 69028646821SStefan Richter }, 69128646821SStefan Richter { } /* Terminating entry */ 69228646821SStefan Richter }; 69328646821SStefan Richter 694fe2af11cSAxel Lin MODULE_DEVICE_TABLE(pci, pci_table); 695fe2af11cSAxel Lin 69628646821SStefan Richter static struct pci_driver lynx_pci_driver = { 697b5e47729SStefan Richter .name = driver_name, 69828646821SStefan Richter .id_table = pci_table, 69928646821SStefan Richter .probe = add_card, 700b5e47729SStefan Richter .remove = remove_card, 70128646821SStefan Richter }; 70228646821SStefan Richter 703fe2af11cSAxel Lin module_pci_driver(lynx_pci_driver); 704fe2af11cSAxel Lin 705b5e47729SStefan Richter MODULE_AUTHOR("Kristian Hoegsberg"); 70628646821SStefan Richter MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers"); 70728646821SStefan Richter MODULE_LICENSE("GPL"); 708