11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers/s390/cio/airq.c 34e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Support for adapter interruptions 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 54e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Copyright IBM Corp. 1999,2007 64e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Author(s): Ingo Adlung <adlung@de.ibm.com> 74e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Cornelia Huck <cornelia.huck@de.ibm.com> 84e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Arnd Bergmann <arndb@de.ibm.com> 94e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rcupdate.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 174e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter#include <asm/airq.h> 18da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck#include <asm/isc.h> 194e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter 204e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter#include "cio.h" 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cio_debug.h" 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 234e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter#define NR_AIRQS 32 244e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter#define NR_AIRQS_PER_WORD sizeof(unsigned long) 254e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter#define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD) 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 274e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiterunion indicator_t { 284e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter unsigned long word[NR_AIRQ_WORDS]; 294e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter unsigned char byte[NR_AIRQS]; 304e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter} __attribute__((packed)); 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 324e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiterstruct airq_t { 334e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter adapter_int_handler_t handler; 344e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter void *drv_data; 354e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter}; 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37a1f640734ab57d548a3fdadad6b869da534d4ecbSebastian Ottstatic union indicator_t indicators[MAX_ISC+1]; 38a1f640734ab57d548a3fdadad6b869da534d4ecbSebastian Ottstatic struct airq_t *airqs[MAX_ISC+1][NR_AIRQS]; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huckstatic int register_airq(struct airq_t *airq, u8 isc) 414e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter{ 424e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter int i; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 444e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter for (i = 0; i < NR_AIRQS; i++) 45da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck if (!cmpxchg(&airqs[isc][i], NULL, airq)) 464e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter return i; 474e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter return -ENOMEM; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 504e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter/** 514e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * s390_register_adapter_interrupt() - register adapter interrupt handler 524e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * @handler: adapter handler to be registered 534e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * @drv_data: driver data passed with each call to the handler 54da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck * @isc: isc for which the handler should be called 554e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * 564e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Returns: 574e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Pointer to the indicator to be used on success 584e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * ERR_PTR() if registration failed 594e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter */ 604e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleitervoid *s390_register_adapter_interrupt(adapter_int_handler_t handler, 61da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck void *drv_data, u8 isc) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 634e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter struct airq_t *airq; 644e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter char dbf_txt[16]; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck if (isc > MAX_ISC) 68da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck return ERR_PTR(-EINVAL); 694e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); 704e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter if (!airq) { 714e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter ret = -ENOMEM; 724e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter goto out; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 744e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter airq->handler = handler; 754e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter airq->drv_data = drv_data; 76da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck 77da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck ret = register_airq(airq, isc); 784e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiterout: 794e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); 804e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter CIO_TRACE_EVENT(4, dbf_txt); 81da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck if (ret < 0) { 82da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck kfree(airq); 834e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter return ERR_PTR(ret); 84da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck } else 85da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck return &indicators[isc].byte[ret]; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 874e8e56c6713398f417317d449f50c08bf2756c66Peter OberparleiterEXPORT_SYMBOL(s390_register_adapter_interrupt); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 894e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter/** 904e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * s390_unregister_adapter_interrupt - unregister adapter interrupt handler 914e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * @ind: indicator for which the handler is to be unregistered 92da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck * @isc: interruption subclass 934e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter */ 94da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huckvoid s390_unregister_adapter_interrupt(void *ind, u8 isc) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 964e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter struct airq_t *airq; 974e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter char dbf_txt[16]; 984e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter int i; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]); 1014e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i); 1024e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter CIO_TRACE_EVENT(4, dbf_txt); 103da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck indicators[isc].byte[i] = 0; 104da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck airq = xchg(&airqs[isc][i], NULL); 1054e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter /* 1064e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Allow interrupts to complete. This will ensure that the airq handle 1074e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * is no longer referenced by any interrupt handler. 1084e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter */ 1094e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter synchronize_sched(); 1104e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter kfree(airq); 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1124e8e56c6713398f417317d449f50c08bf2756c66Peter OberparleiterEXPORT_SYMBOL(s390_unregister_adapter_interrupt); 1134e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter 1144e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 116da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huckvoid do_adapter_IO(u8 isc) 1174e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter{ 1184e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter int w; 1194e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter int i; 1204e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter unsigned long word; 1214e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter struct airq_t *airq; 1224e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter 1234e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter /* 1244e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Access indicator array in word-sized chunks to minimize storage 1254e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * fetch operations. 1264e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter */ 1274e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter for (w = 0; w < NR_AIRQ_WORDS; w++) { 128da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck word = indicators[isc].word[w]; 1294e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter i = w * NR_AIRQS_PER_WORD; 1304e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter /* 1314e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Check bytes within word for active indicators. 1324e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter */ 1334e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter while (word) { 1344e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter if (word & INDICATOR_MASK) { 135da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck airq = airqs[isc][i]; 13687fa5af80cdd5053b27a546725948c2b74ec82b2Heiko Carstens /* Make sure gcc reads from airqs only once. */ 13787fa5af80cdd5053b27a546725948c2b74ec82b2Heiko Carstens barrier(); 1384e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter if (likely(airq)) 139da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck airq->handler(&indicators[isc].byte[i], 1404e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter airq->drv_data); 1414e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter else 1424e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter /* 1434e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter * Reset ill-behaved indicator. 1444e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter */ 145da7c5af82879828409f6b81431ac2f9f353ab04eCornelia Huck indicators[isc].byte[i] = 0; 1464e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter } 1474e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter word <<= 8; 1484e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter i++; 1494e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter } 1504e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter } 1514e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter} 152